#include "internal_includes/toGLSLInstruction.h"
#include "internal_includes/toGLSLOperand.h"
#include "internal_includes/languages.h"
#include "bstrlib.h"
#include "stdio.h"
#include <stdlib.h>
#include "internal_includes/debug.h"

#ifndef min
#define min(a,b)            (((a) < (b)) ? (a) : (b))
#endif

extern void AddIndentation(HLSLCrossCompilerContext* psContext);
static int IsIntegerImmediateOpcode(OPCODE_TYPE eOpcode);

// Calculate the bits set in mask
static int WriteMaskToComponentCount(uint32_t writeMask)
{
	uint32_t count;
	// In HLSL bytecode writemask 0 also means everything
	if (writeMask == 0)
		return 4;

	// Count bits set
	// https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSet64
	count = (writeMask * 0x200040008001ULL & 0x111111111111111ULL) % 0xf;

	return (int)count;
}

static uint32_t BuildComponentMaskFromElementCount(int count)
{
	// Translate numComponents into bitmask
	// 1 -> 1, 2 -> 3, 3 -> 7 and 4 -> 15
	return (1 << count) - 1;
}


// This function prints out the destination name, possible destination writemask, assignment operator
// and any possible conversions needed based on the eSrcType+ui32SrcElementCount (type and size of data expected to be coming in)
// As an output, pNeedsParenthesis will be filled with the amount of closing parenthesis needed
// and pSrcCount will be filled with the number of components expected
// ui32CompMask can be used to only write to 1 or more components (used by MOVC)
static void AddOpAssignToDestWithMask(HLSLCrossCompilerContext* psContext, const Operand* psDest,
	SHADER_VARIABLE_TYPE eSrcType, uint32_t ui32SrcElementCount, const char *szAssignmentOp, int *pNeedsParenthesis, uint32_t ui32CompMask)
{
	uint32_t ui32DestElementCount = GetNumSwizzleElementsWithMask(psDest, ui32CompMask);
	bstring glsl = *psContext->currentGLSLString;
	SHADER_VARIABLE_TYPE eDestDataType = GetOperandDataType(psContext, psDest);
	ASSERT(pNeedsParenthesis != NULL);

	*pNeedsParenthesis = 0;

	TranslateOperandWithMask(psContext, psDest, TO_FLAG_DESTINATION, ui32CompMask);

	// Simple path: types match.
	if (eDestDataType == eSrcType)
	{
		// Cover cases where the HLSL language expects the rest of the components to be default-filled
		// eg. MOV r0, c0.x => Temp[0] = vec4(c0.x);
		if (ui32DestElementCount > ui32SrcElementCount)
		{
			bformata(glsl, " %s %s(", szAssignmentOp, GetConstructorForType(eDestDataType, ui32DestElementCount));
			*pNeedsParenthesis = 1;
		}
		else
			bformata(glsl, " %s ", szAssignmentOp);
		return;
	}

	switch (eDestDataType)
	{
	case SVT_INT:
		if (eSrcType == SVT_FLOAT && psContext->psShader->ui32MajorVersion > 3)
		{
			bformata(glsl, " %s floatBitsToInt(", szAssignmentOp);
			// Cover cases where the HLSL language expects the rest of the components to be default-filled
			if (ui32DestElementCount > ui32SrcElementCount)
			{
				bformata(glsl, "%s(", GetConstructorForType(eSrcType, ui32DestElementCount));
				(*pNeedsParenthesis)++;
			}
		}
		else
			bformata(glsl, " %s %s(", szAssignmentOp, GetConstructorForType(eDestDataType, ui32DestElementCount));
		break;
	case SVT_UINT:
		if (eSrcType == SVT_FLOAT && psContext->psShader->ui32MajorVersion > 3)
		{
			bformata(glsl, " %s floatBitsToUint(", szAssignmentOp);
			// Cover cases where the HLSL language expects the rest of the components to be default-filled
			if (ui32DestElementCount > ui32SrcElementCount)
			{
				bformata(glsl, "%s(", GetConstructorForType(eSrcType, ui32DestElementCount));
				(*pNeedsParenthesis)++;
			}
		}
		else
			bformata(glsl, " %s %s(", szAssignmentOp, GetConstructorForType(eDestDataType, ui32DestElementCount));
		break;

	case SVT_FLOAT:
		if (psContext->psShader->ui32MajorVersion > 3)
		{
			if (eSrcType == SVT_INT)
				bformata(glsl, " %s intBitsToFloat(", szAssignmentOp);
			else
				bformata(glsl, " %s uintBitsToFloat(", szAssignmentOp);
			// Cover cases where the HLSL language expects the rest of the components to be default-filled
			if (ui32DestElementCount > ui32SrcElementCount)
			{
				bformata(glsl, "%s(", GetConstructorForType(eSrcType, ui32DestElementCount));
				(*pNeedsParenthesis)++;
			}

		}
		else
			bformata(glsl, " %s %s(", szAssignmentOp, GetConstructorForType(eDestDataType, ui32DestElementCount));
		break;
	default:
		// TODO: Handle bools?
		break;
	}
	(*pNeedsParenthesis)++;
	return;
}

static void AddAssignToDest(HLSLCrossCompilerContext* psContext, const Operand* psDest,
	SHADER_VARIABLE_TYPE eSrcType, uint32_t ui32SrcElementCount, int* pNeedsParenthesis)
{
	AddOpAssignToDestWithMask(psContext, psDest, eSrcType, ui32SrcElementCount, "=", pNeedsParenthesis, OPERAND_4_COMPONENT_MASK_ALL);
}

static void AddAssignPrologue(HLSLCrossCompilerContext *psContext, int numParenthesis)
{
	bstring glsl = *psContext->currentGLSLString;
	while (numParenthesis != 0)
	{
		bcatcstr(glsl, ")");
		numParenthesis--;
	}
	bcatcstr(glsl, ";\n");

}
static uint32_t ResourceReturnTypeToFlag(const RESOURCE_RETURN_TYPE eType)
{
	if (eType == RETURN_TYPE_SINT)
	{
		return TO_FLAG_INTEGER;
	}
	else if (eType == RETURN_TYPE_UINT)
	{
		return TO_FLAG_UNSIGNED_INTEGER;
	}
	else
	{
		return TO_FLAG_NONE;
	}
}


typedef enum
{
	CMP_EQ,
	CMP_LT,
	CMP_GE,
	CMP_NE,
} ComparisonType;

static void AddComparision(HLSLCrossCompilerContext* psContext, Instruction* psInst, ComparisonType eType,
	uint32_t typeFlag, Instruction* psNextInst)
{
	// Multiple cases to consider here:
	// For shader model <=3: all comparisons are floats
	// otherwise:
	// OPCODE_LT, _GT, _NE etc: inputs are floats, outputs UINT 0xffffffff or 0. typeflag: TO_FLAG_NONE
	// OPCODE_ILT, _IGT etc: comparisons are signed ints, outputs UINT 0xffffffff or 0 typeflag TO_FLAG_INTEGER
	// _ULT, UGT etc: inputs unsigned ints, outputs UINTs typeflag TO_FLAG_UNSIGNED_INTEGER
	// 
	// Additional complexity: if dest swizzle element count is 1, we can use normal comparison operators, otherwise glsl intrinsics.


	bstring glsl = *psContext->currentGLSLString;
	const uint32_t destElemCount = GetNumSwizzleElements(&psInst->asOperands[0]);
	const uint32_t s0ElemCount = GetNumSwizzleElements(&psInst->asOperands[1]);
	const uint32_t s1ElemCount = GetNumSwizzleElements(&psInst->asOperands[2]);
	
	int floatResult = 0;
	int needsParenthesis = 0;

	ASSERT(s0ElemCount == s1ElemCount || s1ElemCount == 1 || s0ElemCount == 1);
	if (s0ElemCount != s1ElemCount)
	{
		// Set the proper auto-expand flag is either argument is scalar
		typeFlag |= (TO_AUTO_EXPAND_TO_VEC2 << (max(s0ElemCount, s1ElemCount)-2));
	}

	if (psContext->psShader->ui32MajorVersion < 4)
	{
		floatResult = 1;
	}

	if (destElemCount > 1)
	{
		const char* glslOpcode[] = {
			"equal",
			"lessThan",
			"greaterThanEqual",
			"notEqual",
		};

		AddIndentation(psContext);
		AddAssignToDest(psContext, &psInst->asOperands[0], floatResult ? SVT_FLOAT : SVT_UINT, destElemCount, &needsParenthesis);

		bcatcstr(glsl, GetConstructorForType(floatResult ? SVT_FLOAT : SVT_UINT, destElemCount));
		bformata(glsl, "(%s(", glslOpcode[eType]);
		TranslateOperand(psContext, &psInst->asOperands[1], typeFlag);
		bcatcstr(glsl, ", ");
		TranslateOperand(psContext, &psInst->asOperands[2], typeFlag);
		bcatcstr(glsl, "))");
		if (!floatResult)
		{
			bcatcstr(glsl, " * 0xFFFFFFFFu");
		}

		AddAssignPrologue(psContext, needsParenthesis);
	}
	else
	{
		const char* glslOpcode[] = {
			"==",
			"<",
			">=",
			"!=",
		};

		//Scalar compare

		// Optimization shortcut for the IGE+BREAKC_NZ combo:
		// First print out the if(cond)->break directly, and then
		// to guarantee correctness with side-effects, re-run
		// the actual comparison. In most cases, the second run will
		// be removed by the shader compiler optimizer pass (dead code elimination)
		// This also makes it easier for some GLSL optimizers to recognize the for loop.

		if (psInst->eOpcode == OPCODE_IGE &&
			psNextInst &&
			psNextInst->eOpcode == OPCODE_BREAKC &&
			(psInst->asOperands[0].ui32RegisterNumber == psNextInst->asOperands[0].ui32RegisterNumber))
		{

			AddIndentation(psContext);
			bcatcstr(glsl, "// IGE+BREAKC opt\n");
			AddIndentation(psContext);

			if (psNextInst->eBooleanTestType == INSTRUCTION_TEST_NONZERO)
				bcatcstr(glsl, "if ((");
			else
				bcatcstr(glsl, "if (!(");
			TranslateOperand(psContext, &psInst->asOperands[1], typeFlag);
			bformata(glsl, "%s ", glslOpcode[eType]);
			TranslateOperand(psContext, &psInst->asOperands[2], typeFlag);
			bcatcstr(glsl, ")) { break; }\n");

			// Mark the BREAKC instruction as already handled
			psNextInst->eOpcode = OPCODE_NOP;

			// Continue as usual
		}

		AddIndentation(psContext);
		AddAssignToDest(psContext, &psInst->asOperands[0], floatResult ? SVT_FLOAT : SVT_UINT, destElemCount, &needsParenthesis);

		bcatcstr(glsl, "(");
		TranslateOperand(psContext, &psInst->asOperands[1], typeFlag);
		bformata(glsl, "%s", glslOpcode[eType]);
		TranslateOperand(psContext, &psInst->asOperands[2], typeFlag);
		if (floatResult)
		{
			bcatcstr(glsl, ") ? 1.0 : 0.0");
		}
		else
		{
			bcatcstr(glsl, ") ? 0xFFFFFFFFu : 0u");
		}
		AddAssignPrologue(psContext, needsParenthesis);
	}
}


static void AddMOVBinaryOp(HLSLCrossCompilerContext* psContext, const Operand *pDest, Operand *pSrc)
{
	int numParenthesis = 0;
	int destComponents = GetMaxComponentFromComponentMask(pDest);
	int srcSwizzleCount = GetNumSwizzleElements(pSrc);
	uint32_t writeMask = GetOperandWriteMask(pDest);

	const SHADER_VARIABLE_TYPE eSrcType = GetOperandDataTypeEx(psContext, pSrc, GetOperandDataType(psContext, pDest));
	uint32_t flags = SVTTypeToFlag(eSrcType);

	AddAssignToDest(psContext, pDest, eSrcType, srcSwizzleCount, &numParenthesis);
	TranslateOperandWithMask(psContext, pSrc, flags, writeMask);

	AddAssignPrologue(psContext, numParenthesis);
}

static uint32_t ElemCountToAutoExpandFlag(uint32_t elemCount)
{
	return TO_AUTO_EXPAND_TO_VEC2 << (elemCount - 2);
}

static void AddMOVCBinaryOp(HLSLCrossCompilerContext* psContext, const Operand *pDest, const Operand *src0, Operand *src1, Operand *src2)
{
	bstring glsl = *psContext->currentGLSLString;
	uint32_t destElemCount = GetNumSwizzleElements(pDest);
	uint32_t s0ElemCount = GetNumSwizzleElements(src0);
	uint32_t s1ElemCount = GetNumSwizzleElements(src1);
	uint32_t s2ElemCount = GetNumSwizzleElements(src2);
	uint32_t destWriteMask = GetOperandWriteMask(pDest);
	uint32_t destElem;

	const SHADER_VARIABLE_TYPE eDestType = GetOperandDataType(psContext, pDest);
	const SHADER_VARIABLE_TYPE eSrc0Type = GetOperandDataType(psContext, src0);
	/*
	for each component in dest[.mask]
	if the corresponding component in src0 (POS-swizzle)
	has any bit set
	{
	copy this component (POS-swizzle) from src1 into dest
	}
	else
	{
	copy this component (POS-swizzle) from src2 into dest
	}
	endfor
	*/

	/* Single-component conditional variable (src0) */
	if (s0ElemCount == 1 || IsSwizzleReplicated(src0))
	{
		int numParenthesis = 0;
		AddIndentation(psContext);
		AddAssignToDest(psContext, pDest, eDestType, destElemCount, &numParenthesis);
		bcatcstr(glsl, "(");
		TranslateOperand(psContext, src0, TO_AUTO_BITCAST_TO_INT);
		if (s0ElemCount > 1)
			bcatcstr(glsl, ".x");
		if (psContext->psShader->ui32MajorVersion < 4)
		{
			//cmp opcode uses >= 0
			bcatcstr(glsl, " >= 0) ? ");
		}
		else
		{
			bcatcstr(glsl, " != 0) ? ");
		}
	
		if (s1ElemCount == 1 && destElemCount > 1)
			TranslateOperand(psContext, src1, SVTTypeToFlag(eDestType) | ElemCountToAutoExpandFlag(destElemCount) );
		else
			TranslateOperandWithMask(psContext, src1, SVTTypeToFlag(eDestType), destWriteMask);

		bcatcstr(glsl, " : ");
		if (s2ElemCount == 1 && destElemCount > 1)
			TranslateOperand(psContext, src2, SVTTypeToFlag(eDestType) | ElemCountToAutoExpandFlag(destElemCount));
		else
			TranslateOperandWithMask(psContext, src2, SVTTypeToFlag(eDestType), destWriteMask);

		AddAssignPrologue(psContext, numParenthesis);
	}
	else
	{
		// TODO: We can actually do this in one op using mix().
		int srcElem = 0;
		for (destElem = 0; destElem < 4; ++destElem)
		{
			int numParenthesis = 0;
			if (pDest->eSelMode == OPERAND_4_COMPONENT_MASK_MODE && pDest->ui32CompMask != 0 && !(pDest->ui32CompMask & (1 << destElem)))
				continue;

			AddIndentation(psContext);
			AddOpAssignToDestWithMask(psContext, pDest, eDestType, 1, "=", &numParenthesis, 1 << destElem);
			bcatcstr(glsl, "(");
			TranslateOperandWithMask(psContext, src0, TO_AUTO_BITCAST_TO_INT, 1 << srcElem);
			if (psContext->psShader->ui32MajorVersion < 4)
			{
				//cmp opcode uses >= 0
				bcatcstr(glsl, " >= 0) ? ");
			}
			else
			{
				bcatcstr(glsl, " != 0) ? ");
			}

			TranslateOperandWithMask(psContext, src1, SVTTypeToFlag(eDestType), 1 << srcElem);
			bcatcstr(glsl, " : ");
			TranslateOperandWithMask(psContext, src2, SVTTypeToFlag(eDestType), 1 << srcElem);

			AddAssignPrologue(psContext, numParenthesis);

			srcElem++;
		}
	}
}

// Returns nonzero if operands are identical, only cares about temp registers currently.
static int AreTempOperandsIdentical(const Operand * psA, const Operand * psB)
{
	if (!psA || !psB)
		return 0;

	if (psA->eType != OPERAND_TYPE_TEMP || psB->eType != OPERAND_TYPE_TEMP)
		return 0;

	if (psA->eModifier != psB->eModifier)
		return 0;

	if (psA->iNumComponents != psB->iNumComponents)
		return 0;

	if (psA->ui32RegisterNumber != psB->ui32RegisterNumber)
		return 0;

	if (psA->eSelMode != psB->eSelMode)
		return 0;

	if (psA->eSelMode == OPERAND_4_COMPONENT_MASK_MODE && psA->ui32CompMask != psB->ui32CompMask)
		return 0;

	if (psA->eSelMode != OPERAND_4_COMPONENT_MASK_MODE && psA->ui32Swizzle != psB->ui32Swizzle)
		return 0;

	return 1;
}

// Returns nonzero if the operation is commutative
static int IsOperationCommutative(OPCODE_TYPE eOpCode)
{
	switch (eOpCode)
	{
	case OPCODE_DADD:
	case OPCODE_IADD:
	case OPCODE_ADD:
	case OPCODE_MUL:
	case OPCODE_IMUL:
	case OPCODE_OR:
	case OPCODE_AND:
		return 1;
	default:
		return 0;
	};
}

static void CallBinaryOp(HLSLCrossCompilerContext* psContext, const char* name, Instruction* psInst,
	int dest, int src0, int src1, SHADER_VARIABLE_TYPE eDataType)
{
	bstring glsl = *psContext->currentGLSLString;
	uint32_t src1SwizCount = GetNumSwizzleElements(&psInst->asOperands[src1]);
	uint32_t src0SwizCount = GetNumSwizzleElements(&psInst->asOperands[src0]);
	uint32_t dstSwizCount = GetNumSwizzleElements(&psInst->asOperands[dest]);
	uint32_t destMask = GetOperandWriteMask(&psInst->asOperands[dest]);
	int needsParenthesis = 0;

	AddIndentation(psContext);

	if (src1SwizCount == src0SwizCount == dstSwizCount)
	{
		// Optimization for readability (and to make for loops in WebGL happy): detect cases where either src == dest and emit +=, -= etc. instead.
		if (AreTempOperandsIdentical(&psInst->asOperands[dest], &psInst->asOperands[src0]) != 0)
		{
			AddOpAssignToDestWithMask(psContext, &psInst->asOperands[dest], eDataType, dstSwizCount, name, &needsParenthesis, OPERAND_4_COMPONENT_MASK_ALL);
			TranslateOperand(psContext, &psInst->asOperands[src1], SVTTypeToFlag(eDataType));
			AddAssignPrologue(psContext, needsParenthesis);
			return;
		}
		else if (AreTempOperandsIdentical(&psInst->asOperands[dest], &psInst->asOperands[src1]) != 0 && (IsOperationCommutative(psInst->eOpcode) != 0))
		{
			AddOpAssignToDestWithMask(psContext, &psInst->asOperands[dest], eDataType, dstSwizCount, name, &needsParenthesis, OPERAND_4_COMPONENT_MASK_ALL);
			TranslateOperand(psContext, &psInst->asOperands[src0], SVTTypeToFlag(eDataType));
			AddAssignPrologue(psContext, needsParenthesis);
			return;
		}
	}

	AddAssignToDest(psContext, &psInst->asOperands[dest], eDataType, dstSwizCount, &needsParenthesis);

	TranslateOperandWithMask(psContext, &psInst->asOperands[src0], SVTTypeToFlag(eDataType), destMask);
	bformata(glsl, " %s ", name);
	TranslateOperandWithMask(psContext, &psInst->asOperands[src1], SVTTypeToFlag(eDataType), destMask);
	AddAssignPrologue(psContext, needsParenthesis);
}

static void CallTernaryOp(HLSLCrossCompilerContext* psContext, const char* op1, const char* op2, Instruction* psInst,
	int dest, int src0, int src1, int src2, uint32_t dataType)
{
	bstring glsl = *psContext->currentGLSLString;
	uint32_t src2SwizCount = GetNumSwizzleElements(&psInst->asOperands[src2]);
	uint32_t src1SwizCount = GetNumSwizzleElements(&psInst->asOperands[src1]);
	uint32_t src0SwizCount = GetNumSwizzleElements(&psInst->asOperands[src0]);
	uint32_t dstSwizCount = GetNumSwizzleElements(&psInst->asOperands[dest]);
	uint32_t destMask = GetOperandWriteMask(&psInst->asOperands[dest]);

	uint32_t ui32Flags = dataType;
	int numParenthesis = 0;

	AddIndentation(psContext);

	AddAssignToDest(psContext, &psInst->asOperands[dest], TypeFlagsToSVTType(dataType), dstSwizCount, &numParenthesis);

	TranslateOperandWithMask(psContext, &psInst->asOperands[src0], ui32Flags, destMask);
	bformata(glsl, " %s ", op1);
	TranslateOperandWithMask(psContext, &psInst->asOperands[src1], ui32Flags, destMask);
	bformata(glsl, " %s ", op2);
	TranslateOperandWithMask(psContext, &psInst->asOperands[src2], ui32Flags, destMask);
	AddAssignPrologue(psContext, numParenthesis);
}

static void CallHelper3(HLSLCrossCompilerContext* psContext, const char* name, Instruction* psInst,
	int dest, int src0, int src1, int src2, int paramsShouldFollowWriteMask)
{
	uint32_t ui32Flags = TO_AUTO_BITCAST_TO_FLOAT;
	bstring glsl = *psContext->currentGLSLString;
	uint32_t destMask = paramsShouldFollowWriteMask ? GetOperandWriteMask(&psInst->asOperands[dest]) : OPERAND_4_COMPONENT_MASK_ALL;
	uint32_t src2SwizCount = GetNumSwizzleElements(&psInst->asOperands[src2]);
	uint32_t src1SwizCount = GetNumSwizzleElements(&psInst->asOperands[src1]);
	uint32_t src0SwizCount = GetNumSwizzleElements(&psInst->asOperands[src0]);
	uint32_t dstSwizCount = GetNumSwizzleElements(&psInst->asOperands[dest]);
	int numParenthesis = 0;


	AddIndentation(psContext);
	
	AddAssignToDest(psContext, &psInst->asOperands[dest], SVT_FLOAT, dstSwizCount, &numParenthesis);

	bformata(glsl, "%s(", name);
	numParenthesis++;
	TranslateOperandWithMask(psContext, &psInst->asOperands[src0], ui32Flags, destMask);
	bcatcstr(glsl, ", ");
	TranslateOperandWithMask(psContext, &psInst->asOperands[src1], ui32Flags, destMask);
	bcatcstr(glsl, ", ");
	TranslateOperandWithMask(psContext, &psInst->asOperands[src2], ui32Flags, destMask);
	AddAssignPrologue(psContext, numParenthesis);
}

static void CallHelper2(HLSLCrossCompilerContext* psContext, const char* name, Instruction* psInst,
	int dest, int src0, int src1, int paramsShouldFollowWriteMask)
{
	uint32_t ui32Flags = TO_AUTO_BITCAST_TO_FLOAT;
	bstring glsl = *psContext->currentGLSLString;
	uint32_t destMask = paramsShouldFollowWriteMask ? GetOperandWriteMask(&psInst->asOperands[dest]) : OPERAND_4_COMPONENT_MASK_ALL;
	uint32_t src1SwizCount = GetNumSwizzleElements(&psInst->asOperands[src1]);
	uint32_t src0SwizCount = GetNumSwizzleElements(&psInst->asOperands[src0]);
	uint32_t dstSwizCount = GetNumSwizzleElements(&psInst->asOperands[dest]);

	int isDotProduct = (strncmp(name, "dot", 3) == 0) ? 1 : 0;
	int numParenthesis = 0;

	AddIndentation(psContext);
	AddAssignToDest(psContext, &psInst->asOperands[dest], SVT_FLOAT, isDotProduct ? 1 : dstSwizCount, &numParenthesis);

	bformata(glsl, "%s(", name);
	numParenthesis++;

	TranslateOperandWithMask(psContext, &psInst->asOperands[src0], ui32Flags, destMask);
	bcatcstr(glsl, ", ");
	TranslateOperandWithMask(psContext, &psInst->asOperands[src1], ui32Flags, destMask);

	AddAssignPrologue(psContext, numParenthesis);
}

static void CallHelper2Int(HLSLCrossCompilerContext* psContext, const char* name, Instruction* psInst,
	int dest, int src0, int src1, int paramsShouldFollowWriteMask)
{
	uint32_t ui32Flags = TO_AUTO_BITCAST_TO_INT;
	bstring glsl = *psContext->currentGLSLString;
	uint32_t src1SwizCount = GetNumSwizzleElements(&psInst->asOperands[src1]);
	uint32_t src0SwizCount = GetNumSwizzleElements(&psInst->asOperands[src0]);
	uint32_t dstSwizCount = GetNumSwizzleElements(&psInst->asOperands[dest]);
	uint32_t destMask = paramsShouldFollowWriteMask ? GetOperandWriteMask(&psInst->asOperands[dest]) : OPERAND_4_COMPONENT_MASK_ALL;
	int numParenthesis = 0;

	AddIndentation(psContext);

	AddAssignToDest(psContext, &psInst->asOperands[dest], SVT_INT, dstSwizCount, &numParenthesis);

	bformata(glsl, "%s(", name);
	numParenthesis++;
	TranslateOperandWithMask(psContext, &psInst->asOperands[src0], ui32Flags, destMask);
	bcatcstr(glsl, ", ");
	TranslateOperandWithMask(psContext, &psInst->asOperands[src1], ui32Flags, destMask);
	AddAssignPrologue(psContext, numParenthesis);
}

static void CallHelper2UInt(HLSLCrossCompilerContext* psContext, const char* name, Instruction* psInst,
	int dest, int src0, int src1, int paramsShouldFollowWriteMask)
{
	uint32_t ui32Flags = TO_AUTO_BITCAST_TO_UINT;
	bstring glsl = *psContext->currentGLSLString;
	uint32_t src1SwizCount = GetNumSwizzleElements(&psInst->asOperands[src1]);
	uint32_t src0SwizCount = GetNumSwizzleElements(&psInst->asOperands[src0]);
	uint32_t dstSwizCount = GetNumSwizzleElements(&psInst->asOperands[dest]);
	uint32_t destMask = paramsShouldFollowWriteMask ? GetOperandWriteMask(&psInst->asOperands[dest]) : OPERAND_4_COMPONENT_MASK_ALL;
	int numParenthesis = 0;

	AddIndentation(psContext);

	AddAssignToDest(psContext, &psInst->asOperands[dest], SVT_UINT, dstSwizCount, &numParenthesis);

	bformata(glsl, "%s(", name);
	numParenthesis++;
	TranslateOperandWithMask(psContext, &psInst->asOperands[src0], ui32Flags, destMask);
	bcatcstr(glsl, ", ");
	TranslateOperandWithMask(psContext, &psInst->asOperands[src1], ui32Flags, destMask);
	AddAssignPrologue(psContext, numParenthesis);
}

static void CallHelper1(HLSLCrossCompilerContext* psContext, const char* name, Instruction* psInst,
	int dest, int src0, int paramsShouldFollowWriteMask)
{
	uint32_t ui32Flags = TO_AUTO_BITCAST_TO_FLOAT;
	bstring glsl = *psContext->currentGLSLString;
	uint32_t src0SwizCount = GetNumSwizzleElements(&psInst->asOperands[src0]);
	uint32_t dstSwizCount = GetNumSwizzleElements(&psInst->asOperands[dest]);
	uint32_t destMask = paramsShouldFollowWriteMask ? GetOperandWriteMask(&psInst->asOperands[dest]) : OPERAND_4_COMPONENT_MASK_ALL;
	int numParenthesis = 0;

	AddIndentation(psContext);

	AddAssignToDest(psContext, &psInst->asOperands[dest], SVT_FLOAT, dstSwizCount, &numParenthesis);

	bformata(glsl, "%s(", name);
	numParenthesis++;
	TranslateOperandWithMask(psContext, &psInst->asOperands[src0], ui32Flags, destMask);
	AddAssignPrologue(psContext, numParenthesis);
}

//Result is an int.
static void CallHelper1Int(HLSLCrossCompilerContext* psContext,
	const char* name,
	Instruction* psInst,
	const int dest,
	const int src0,
	int paramsShouldFollowWriteMask)
{
	uint32_t ui32Flags = TO_AUTO_BITCAST_TO_INT;
	bstring glsl = *psContext->currentGLSLString;
	uint32_t src0SwizCount = GetNumSwizzleElements(&psInst->asOperands[src0]);
	uint32_t dstSwizCount = GetNumSwizzleElements(&psInst->asOperands[dest]);
	uint32_t destMask = paramsShouldFollowWriteMask ? GetOperandWriteMask(&psInst->asOperands[dest]) : OPERAND_4_COMPONENT_MASK_ALL;
	int numParenthesis = 0;

	AddIndentation(psContext);

	AddAssignToDest(psContext, &psInst->asOperands[dest], SVT_INT, dstSwizCount, &numParenthesis);

	bformata(glsl, "%s(", name);
	numParenthesis++;
	TranslateOperandWithMask(psContext, &psInst->asOperands[src0], ui32Flags, destMask);
	AddAssignPrologue(psContext, numParenthesis);
}

static void TranslateTexelFetch(HLSLCrossCompilerContext* psContext,
	Instruction* psInst,
	ResourceBinding* psBinding,
	bstring glsl)
{
	int numParenthesis = 0;
	uint32_t destCount = GetNumSwizzleElements(&psInst->asOperands[0]);
	AddIndentation(psContext);
	AddAssignToDest(psContext, &psInst->asOperands[0], TypeFlagsToSVTType(ResourceReturnTypeToFlag(psBinding->ui32ReturnType)), 4, &numParenthesis);
	bcatcstr(glsl, "texelFetch(");

	switch (psBinding->eDimension)
	{
	case REFLECT_RESOURCE_DIMENSION_TEXTURE1D:
	case REFLECT_RESOURCE_DIMENSION_BUFFER:
	{
		TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NONE);
		bcatcstr(glsl, ", ");
		TranslateOperandWithMask(psContext, &psInst->asOperands[1], TO_FLAG_INTEGER, OPERAND_4_COMPONENT_MASK_X);
		if (psBinding->eDimension != REFLECT_RESOURCE_DIMENSION_BUFFER)
			bcatcstr(glsl, ", 0"); // Buffers don't have LOD
		bcatcstr(glsl, ")");
		break;
	}
	case REFLECT_RESOURCE_DIMENSION_TEXTURE2DARRAY:
	case REFLECT_RESOURCE_DIMENSION_TEXTURE3D:
	{
		TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NONE);
		bcatcstr(glsl, ", ");
		TranslateOperandWithMask(psContext, &psInst->asOperands[1], TO_FLAG_INTEGER | TO_AUTO_EXPAND_TO_VEC3, 7 /* .xyz */);
		bcatcstr(glsl, ", 0)");
		break;
	}
	case REFLECT_RESOURCE_DIMENSION_TEXTURE2D:
	case REFLECT_RESOURCE_DIMENSION_TEXTURE1DARRAY:
	{
		TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NONE);
		bcatcstr(glsl, ", ");
		TranslateOperandWithMask(psContext, &psInst->asOperands[1], TO_FLAG_INTEGER | TO_AUTO_EXPAND_TO_VEC2, 3 /* .xy */);
		bcatcstr(glsl, ", 0)");
		break;
	}
	case REFLECT_RESOURCE_DIMENSION_TEXTURE2DMS: // TODO does this make any sense at all?
	{
		ASSERT(psInst->eOpcode == OPCODE_LD_MS);
		TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NONE);
		bcatcstr(glsl, ", ");
		TranslateOperandWithMask(psContext, &psInst->asOperands[1], TO_FLAG_INTEGER | TO_AUTO_EXPAND_TO_VEC2, 3 /* .xy */);
		bcatcstr(glsl, ", ");
		TranslateOperandWithMask(psContext, &psInst->asOperands[3], TO_FLAG_INTEGER, OPERAND_4_COMPONENT_MASK_X);
		bcatcstr(glsl, ")");
		break;
	}
	case REFLECT_RESOURCE_DIMENSION_TEXTURE2DMSARRAY:
	{
		ASSERT(psInst->eOpcode == OPCODE_LD_MS);
		TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NONE);
		bcatcstr(glsl, ", ");
		TranslateOperandWithMask(psContext, &psInst->asOperands[1], TO_FLAG_INTEGER | TO_AUTO_EXPAND_TO_VEC3, 7 /* .xyz */);
		bcatcstr(glsl, ", ");
		TranslateOperandWithMask(psContext, &psInst->asOperands[3], TO_FLAG_INTEGER, OPERAND_4_COMPONENT_MASK_X);
		bcatcstr(glsl, ")");
		break;
	}
	case REFLECT_RESOURCE_DIMENSION_TEXTURECUBE:
	case REFLECT_RESOURCE_DIMENSION_TEXTURECUBEARRAY:
	case REFLECT_RESOURCE_DIMENSION_BUFFEREX:
	default:
	{
		ASSERT(0);
		break;
	}
	}

	AddSwizzleUsingElementCount(psContext, destCount);
	AddAssignPrologue(psContext, numParenthesis);
}

static void TranslateTexelFetchOffset(HLSLCrossCompilerContext* psContext,
	Instruction* psInst,
	ResourceBinding* psBinding,
	bstring glsl)
{
	int numParenthesis = 0;
	uint32_t destCount = GetNumSwizzleElements(&psInst->asOperands[0]);
	AddIndentation(psContext);
	AddAssignToDest(psContext, &psInst->asOperands[0], TypeFlagsToSVTType(ResourceReturnTypeToFlag(psBinding->ui32ReturnType)), 4, &numParenthesis);

	bcatcstr(glsl, "texelFetchOffset(");

	switch (psBinding->eDimension)
	{
	case REFLECT_RESOURCE_DIMENSION_TEXTURE1D:
	{
		TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NONE);
		bcatcstr(glsl, ", ");
		TranslateOperandWithMask(psContext, &psInst->asOperands[1], TO_FLAG_INTEGER, OPERAND_4_COMPONENT_MASK_X);
		bformata(glsl, ", 0, %d)", psInst->iUAddrOffset);
		break;
	}
	case REFLECT_RESOURCE_DIMENSION_TEXTURE2DARRAY:
	{
		TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NONE);
		bcatcstr(glsl, ", ");
		TranslateOperandWithMask(psContext, &psInst->asOperands[1], TO_FLAG_INTEGER | TO_AUTO_EXPAND_TO_VEC3, 7 /* .xyz */);
		bformata(glsl, ", 0, ivec2(%d, %d))",
			psInst->iUAddrOffset,
			psInst->iVAddrOffset);
		break;
	}
	case REFLECT_RESOURCE_DIMENSION_TEXTURE3D:
	{
		TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NONE);
		bcatcstr(glsl, ", ");
		TranslateOperandWithMask(psContext, &psInst->asOperands[1], TO_FLAG_INTEGER | TO_AUTO_EXPAND_TO_VEC3, 7 /* .xyz */);
		bformata(glsl, ", 0, ivec3(%d, %d, %d))",
			psInst->iUAddrOffset,
			psInst->iVAddrOffset,
			psInst->iWAddrOffset);
		break;
	}
	case REFLECT_RESOURCE_DIMENSION_TEXTURE2D:
	{
		TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NONE);
		bcatcstr(glsl, ", ");
		TranslateOperandWithMask(psContext, &psInst->asOperands[1], TO_FLAG_INTEGER | TO_AUTO_EXPAND_TO_VEC2, 3 /* .xy */);
		bformata(glsl, ", 0, ivec2(%d, %d))", psInst->iUAddrOffset, psInst->iVAddrOffset);
		break;
	}
	case REFLECT_RESOURCE_DIMENSION_TEXTURE1DARRAY:
	{
		TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NONE);
		bcatcstr(glsl, ", ");
		TranslateOperandWithMask(psContext, &psInst->asOperands[1], TO_FLAG_INTEGER | TO_AUTO_EXPAND_TO_VEC2, 3 /* .xy */);
		bformata(glsl, ", 0, int(%d))", psInst->iUAddrOffset);
		break;
	}
	case REFLECT_RESOURCE_DIMENSION_BUFFER:
	case REFLECT_RESOURCE_DIMENSION_TEXTURE2DMS:
	case REFLECT_RESOURCE_DIMENSION_TEXTURE2DMSARRAY:
	case REFLECT_RESOURCE_DIMENSION_TEXTURECUBE:
	case REFLECT_RESOURCE_DIMENSION_TEXTURECUBEARRAY:
	case REFLECT_RESOURCE_DIMENSION_BUFFEREX:
	default:
	{
		ASSERT(0);
		break;
	}
	}

	AddSwizzleUsingElementCount(psContext, destCount);
	AddAssignPrologue(psContext, numParenthesis);
}


//Makes sure the texture coordinate swizzle is appropriate for the texture type.
//i.e. vecX for X-dimension texture.
//Currently supports floating point coord only, so not used for texelFetch.
static void TranslateTexCoord(HLSLCrossCompilerContext* psContext,
	const RESOURCE_DIMENSION eResDim,
	Operand* psTexCoordOperand)
{
	int numParenthesis = 0;
	uint32_t flags = TO_AUTO_BITCAST_TO_FLOAT;
	bstring glsl = *psContext->currentGLSLString;
	uint32_t opMask = OPERAND_4_COMPONENT_MASK_ALL;

	switch (eResDim)
	{
	case RESOURCE_DIMENSION_TEXTURE1D:
	{
		//Vec1 texcoord. Mask out the other components.
		opMask = OPERAND_4_COMPONENT_MASK_X;
		break;
	}
	case RESOURCE_DIMENSION_TEXTURE2D:
	case RESOURCE_DIMENSION_TEXTURE1DARRAY:
	{
		//Vec2 texcoord. Mask out the other components.
		opMask = OPERAND_4_COMPONENT_MASK_X | OPERAND_4_COMPONENT_MASK_Y;
		flags |= TO_AUTO_EXPAND_TO_VEC2;
		break;
	}
	case RESOURCE_DIMENSION_TEXTURECUBE:
	case RESOURCE_DIMENSION_TEXTURE3D:
	case RESOURCE_DIMENSION_TEXTURE2DARRAY:
	{
		//Vec3 texcoord. Mask out the other components.
		opMask = OPERAND_4_COMPONENT_MASK_X | OPERAND_4_COMPONENT_MASK_Y | OPERAND_4_COMPONENT_MASK_Z;
		flags |= TO_AUTO_EXPAND_TO_VEC3;
		break;
	}
	case RESOURCE_DIMENSION_TEXTURECUBEARRAY:
	{
		flags |= TO_AUTO_EXPAND_TO_VEC4;
		break;
	}
	default:
	{
		ASSERT(0);
		break;
	}
	}

	//FIXME detect when integer coords are needed.
	TranslateOperandWithMask(psContext, psTexCoordOperand, flags, opMask);
}

static int GetNumTextureDimensions(HLSLCrossCompilerContext* psContext,
	const RESOURCE_DIMENSION eResDim)
{
	int constructor = 0;
	bstring glsl = *psContext->currentGLSLString;

	switch (eResDim)
	{
	case RESOURCE_DIMENSION_TEXTURE1D:
	{
		return 1;
	}
	case RESOURCE_DIMENSION_TEXTURE2D:
	case RESOURCE_DIMENSION_TEXTURE1DARRAY:
	case RESOURCE_DIMENSION_TEXTURECUBE:
	{
		return 2;
	}

	case RESOURCE_DIMENSION_TEXTURE3D:
	case RESOURCE_DIMENSION_TEXTURE2DARRAY:
	case RESOURCE_DIMENSION_TEXTURECUBEARRAY:
	{
		return 3;
	}
	default:
	{
		ASSERT(0);
		break;
	}
	}
	return 0;
}

void GetResInfoData(HLSLCrossCompilerContext* psContext, Instruction* psInst, int index, int destElem)
{
	bstring glsl = *psContext->currentGLSLString;
	int numParenthesis = 0;
	const RESINFO_RETURN_TYPE eResInfoReturnType = psInst->eResInfoReturnType;
	const RESOURCE_DIMENSION eResDim = psContext->psShader->aeResourceDims[psInst->asOperands[2].ui32RegisterNumber];

	AddIndentation(psContext);
	AddOpAssignToDestWithMask(psContext, &psInst->asOperands[0], eResInfoReturnType == RESINFO_INSTRUCTION_RETURN_UINT ? SVT_UINT : SVT_FLOAT, 1, "=", &numParenthesis, 1 << destElem);

	//[width, height, depth or array size, total-mip-count]
	if (index < 3)
	{
		int dim = GetNumTextureDimensions(psContext, eResDim);
		bcatcstr(glsl, "(");
		if (dim < (index + 1))
		{
			bcatcstr(glsl, eResInfoReturnType == RESINFO_INSTRUCTION_RETURN_UINT ? "0u" : "0.0");
		}
		else
		{
			if (eResInfoReturnType == RESINFO_INSTRUCTION_RETURN_UINT)
			{
				bformata(glsl, "uvec%d(textureSize(", dim);
			}
			else if (eResInfoReturnType == RESINFO_INSTRUCTION_RETURN_RCPFLOAT)
			{
				bformata(glsl, "vec%d(1.0) / vec%d(textureSize(", dim, dim);
			}
			else
			{
				bformata(glsl, "vec%d(textureSize(", dim);
			}
			TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NONE);
			bcatcstr(glsl, ", ");
			TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_INTEGER);
			bcatcstr(glsl, "))");

			switch (index)
			{
			case 0:
				bcatcstr(glsl, ".x");
				break;
			case 1:
				bcatcstr(glsl, ".y");
				break;
			case 2:
				bcatcstr(glsl, ".z");
				break;
			}
		}

		bcatcstr(glsl, ")");
	}
	else
	{
		if (eResInfoReturnType == RESINFO_INSTRUCTION_RETURN_UINT)
			bcatcstr(glsl, "uint(");
		else
			bcatcstr(glsl, "float(");
		bcatcstr(glsl, "textureQueryLevels(");
		TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NONE);
		bcatcstr(glsl, "))");
	}
	AddAssignPrologue(psContext, numParenthesis);
}

#define TEXSMP_FLAG_NONE 0x0
#define TEXSMP_FLAG_LOD 0x1 //LOD comes from operand
#define TEXSMP_FLAG_DEPTHCOMPARE 0x2
#define TEXSMP_FLAG_FIRSTLOD 0x4 //LOD is 0
#define TEXSMP_FLAG_BIAS 0x8
#define TEXSMP_FLAGS_GRAD 0x10

// TODO FIXME: non-float samplers!
static void TranslateTextureSample(HLSLCrossCompilerContext* psContext, Instruction* psInst,
	uint32_t ui32Flags)
{
	bstring glsl = *psContext->currentGLSLString;
	uint32_t numParenthesis = 0;

	const char* funcName = "texture";
	const char* offset = "";
	const char* depthCmpCoordType = "";
	const char* gradSwizzle = "";

	uint32_t ui32NumOffsets = 0;

	const RESOURCE_DIMENSION eResDim = psContext->psShader->aeResourceDims[psInst->asOperands[2].ui32RegisterNumber];

	const int iHaveOverloadedTexFuncs = HaveOverloadedTextureFuncs(psContext->psShader->eTargetLanguage);

	const int useCombinedTextureSamplers = (psContext->flags & HLSLCC_FLAG_COMBINE_TEXTURE_SAMPLERS) ? 1 : 0;

	ASSERT(psInst->asOperands[2].ui32RegisterNumber < MAX_TEXTURES);

	if (psInst->bAddressOffset)
	{
		offset = "Offset";
	}

	switch (eResDim)
	{
	case RESOURCE_DIMENSION_TEXTURE1D:
	{
		depthCmpCoordType = "vec2";
		gradSwizzle = ".x";
		ui32NumOffsets = 1;
		if (!iHaveOverloadedTexFuncs)
		{
			funcName = "texture1D";
			if (ui32Flags & TEXSMP_FLAG_DEPTHCOMPARE)
			{
				funcName = "shadow1D";
			}
		}
		break;
	}
	case RESOURCE_DIMENSION_TEXTURE2D:
	{
		depthCmpCoordType = "vec3";
		gradSwizzle = ".xy";
		ui32NumOffsets = 2;
		if (!iHaveOverloadedTexFuncs)
		{
			funcName = "texture2D";
			if (ui32Flags & TEXSMP_FLAG_DEPTHCOMPARE)
			{
				funcName = "shadow2D";
			}
		}
		break;
	}
	case RESOURCE_DIMENSION_TEXTURECUBE:
	{
		depthCmpCoordType = "vec3";
		gradSwizzle = ".xyz";
		ui32NumOffsets = 3;
		if (!iHaveOverloadedTexFuncs)
		{
			funcName = "textureCube";
		}
		break;
	}
	case RESOURCE_DIMENSION_TEXTURE3D:
	{
		depthCmpCoordType = "vec4";
		gradSwizzle = ".xyz";
		ui32NumOffsets = 3;
		if (!iHaveOverloadedTexFuncs)
		{
			funcName = "texture3D";
		}
		break;
	}
	case RESOURCE_DIMENSION_TEXTURE1DARRAY:
	{
		depthCmpCoordType = "vec3";
		gradSwizzle = ".x";
		ui32NumOffsets = 1;
		break;
	}
	case RESOURCE_DIMENSION_TEXTURE2DARRAY:
	{
		depthCmpCoordType = "vec4";
		gradSwizzle = ".xy";
		ui32NumOffsets = 2;
		break;
	}
	case RESOURCE_DIMENSION_TEXTURECUBEARRAY:
	{
		gradSwizzle = ".xyz";
		ui32NumOffsets = 3;
		if (ui32Flags & TEXSMP_FLAG_DEPTHCOMPARE)
		{
			SHADER_VARIABLE_TYPE dataType = SVT_FLOAT; // TODO!!
			//Special. Reference is a separate argument.
			AddIndentation(psContext);

			AddAssignToDest(psContext, &psInst->asOperands[0], dataType, 1, &numParenthesis);
			if (ui32Flags & (TEXSMP_FLAG_LOD | TEXSMP_FLAG_FIRSTLOD))
			{
				bcatcstr(glsl, "textureLod(");
			}
			else
			{
				bcatcstr(glsl, "texture(");
			}
			if (!useCombinedTextureSamplers)
				ResourceName(glsl, psContext, RGROUP_TEXTURE, psInst->asOperands[2].ui32RegisterNumber, (ui32Flags & TEXSMP_FLAG_DEPTHCOMPARE) ? 1 : 0);
			else
				bconcat(glsl, TextureSamplerName(&psContext->psShader->sInfo, psInst->asOperands[2].ui32RegisterNumber, psInst->asOperands[3].ui32RegisterNumber, (ui32Flags & TEXSMP_FLAG_DEPTHCOMPARE) ? 1 : 0));
			bcatcstr(glsl, ",");
			TranslateTexCoord(psContext, eResDim, &psInst->asOperands[1]);
			bcatcstr(glsl, ",");
			//.z = reference.
			TranslateOperand(psContext, &psInst->asOperands[4], TO_AUTO_BITCAST_TO_FLOAT);

			if (ui32Flags & TEXSMP_FLAG_FIRSTLOD)
			{
				bcatcstr(glsl, ", 0.0");
			}

			bcatcstr(glsl, ")");
			// Doesn't make any sense to do swizzles here, depth comparison returns a scalar.
			AddAssignPrologue(psContext, numParenthesis);
			return;
		}

		break;
	}
	default:
	{
		ASSERT(0);
		break;
	}
	}

	if (ui32Flags & TEXSMP_FLAG_DEPTHCOMPARE)
	{
		//For non-cubeMap Arrays the reference value comes from the
		//texture coord vector in GLSL. For cubmap arrays there is a
		//separate parameter.
		//It is always separate paramter in HLSL.
		SHADER_VARIABLE_TYPE dataType = SVT_FLOAT; // TODO!!
		AddIndentation(psContext);
		AddAssignToDest(psContext, &psInst->asOperands[0], dataType, GetNumSwizzleElements(&psInst->asOperands[2]), &numParenthesis);
		if (ui32Flags & (TEXSMP_FLAG_LOD | TEXSMP_FLAG_FIRSTLOD))
		{
			bformata(glsl, "%sLod%s(", funcName, offset);
		}
		else
		{
			bformata(glsl, "%s%s(", funcName, offset);
		}
		if (!useCombinedTextureSamplers)
			ResourceName(glsl, psContext, RGROUP_TEXTURE, psInst->asOperands[2].ui32RegisterNumber, 1);
		else
			bconcat(glsl, TextureSamplerName(&psContext->psShader->sInfo, psInst->asOperands[2].ui32RegisterNumber, psInst->asOperands[3].ui32RegisterNumber, 1));
		bformata(glsl, ", %s(", depthCmpCoordType);
		TranslateTexCoord(psContext, eResDim, &psInst->asOperands[1]);
		bcatcstr(glsl, ",");
		//.z = reference.
		TranslateOperand(psContext, &psInst->asOperands[4], TO_AUTO_BITCAST_TO_FLOAT);
		bcatcstr(glsl, ")");

		if (ui32Flags & TEXSMP_FLAG_FIRSTLOD)
		{
			bcatcstr(glsl, ", 0.0");
		}

		bcatcstr(glsl, ")");
	}
	else
	{
		SHADER_VARIABLE_TYPE dataType = SVT_FLOAT; // TODO!!
		AddIndentation(psContext);
		AddAssignToDest(psContext, &psInst->asOperands[0], dataType, GetNumSwizzleElements(&psInst->asOperands[2]), &numParenthesis);

		if (ui32Flags & (TEXSMP_FLAG_LOD | TEXSMP_FLAG_FIRSTLOD))
		{
			bformata(glsl, "%sLod%s(", funcName, offset);
		}
		else
			if (ui32Flags & TEXSMP_FLAGS_GRAD)
			{
			bformata(glsl, "%sGrad%s(", funcName, offset);
			}
			else
			{
				bformata(glsl, "%s%s(", funcName, offset);
			}
		if (!useCombinedTextureSamplers)
			TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NONE);//resource
		else
			bconcat(glsl, TextureSamplerName(&psContext->psShader->sInfo, psInst->asOperands[2].ui32RegisterNumber, psInst->asOperands[3].ui32RegisterNumber, 0));
		bcatcstr(glsl, ", ");
		TranslateTexCoord(psContext, eResDim, &psInst->asOperands[1]);

		if (ui32Flags & (TEXSMP_FLAG_LOD))
		{
			bcatcstr(glsl, ", ");
			TranslateOperand(psContext, &psInst->asOperands[4], TO_AUTO_BITCAST_TO_FLOAT);
			if (psContext->psShader->ui32MajorVersion < 4)
			{
				bcatcstr(glsl, ".w");
			}
		}
		else
			if (ui32Flags & TEXSMP_FLAG_FIRSTLOD)
			{
			bcatcstr(glsl, ", 0.0");
			}
			else
				if (ui32Flags & TEXSMP_FLAGS_GRAD)
				{
			bcatcstr(glsl, ", vec4(");
			TranslateOperand(psContext, &psInst->asOperands[4], TO_AUTO_BITCAST_TO_FLOAT);//dx
			bcatcstr(glsl, ")");
			bcatcstr(glsl, gradSwizzle);
			bcatcstr(glsl, ", vec4(");
			TranslateOperand(psContext, &psInst->asOperands[5], TO_AUTO_BITCAST_TO_FLOAT);//dy
			bcatcstr(glsl, ")");
			bcatcstr(glsl, gradSwizzle);
				}

		if (psInst->bAddressOffset)
		{
			if (ui32NumOffsets == 1)
			{
				bformata(glsl, ", %d",
					psInst->iUAddrOffset);
			}
			else
				if (ui32NumOffsets == 2)
				{
				bformata(glsl, ", ivec2(%d, %d)",
					psInst->iUAddrOffset,
					psInst->iVAddrOffset);
				}
				else
					if (ui32NumOffsets == 3)
					{
				bformata(glsl, ", ivec3(%d, %d, %d)",
					psInst->iUAddrOffset,
					psInst->iVAddrOffset,
					psInst->iWAddrOffset);
					}
		}

		if (ui32Flags & (TEXSMP_FLAG_BIAS))
		{
			bcatcstr(glsl, ", ");
			TranslateOperand(psContext, &psInst->asOperands[4], TO_AUTO_BITCAST_TO_FLOAT);
		}

		bcatcstr(glsl, ")");
	}

	if (!(ui32Flags & TEXSMP_FLAG_DEPTHCOMPARE))
	{
		// iWriteMaskEnabled is forced off during DecodeOperand because swizzle on sampler uniforms
		// does not make sense. But need to re-enable to correctly swizzle this particular instruction.
		psInst->asOperands[2].iWriteMaskEnabled = 1;
		TranslateOperandSwizzleWithMask(psContext, &psInst->asOperands[2], GetOperandWriteMask(&psInst->asOperands[0]));
	}
	AddAssignPrologue(psContext, numParenthesis);
}

static ShaderVarType* LookupStructuredVar(HLSLCrossCompilerContext* psContext,
	Operand* psResource,
	Operand* psByteOffset,
	uint32_t ui32Component)
{
	ConstantBuffer* psCBuf = NULL;
	ShaderVarType* psVarType = NULL;
	uint32_t aui32Swizzle[4] = { OPERAND_4_COMPONENT_X };
	int byteOffset = ((int*)psByteOffset->afImmediates)[0] + 4 * ui32Component;
	int vec4Offset = 0;
	int32_t index = -1;
	int32_t rebase = -1;
	int found;

	ASSERT(psByteOffset->eType == OPERAND_TYPE_IMMEDIATE32);
	//TODO: multi-component stores and vector writes need testing.

	//aui32Swizzle[0] = psInst->asOperands[0].aui32Swizzle[component];

	switch (byteOffset % 16)
	{
	case 0:
		aui32Swizzle[0] = 0;
		break;
	case 4:
		aui32Swizzle[0] = 1;
		break;
	case 8:
		aui32Swizzle[0] = 2;
		break;
	case 12:
		aui32Swizzle[0] = 3;
		break;
	}

	switch (psResource->eType)
	{
	case OPERAND_TYPE_RESOURCE:
		GetConstantBufferFromBindingPoint(RGROUP_TEXTURE, psResource->ui32RegisterNumber, &psContext->psShader->sInfo, &psCBuf);
		break;
	case OPERAND_TYPE_UNORDERED_ACCESS_VIEW:
		GetConstantBufferFromBindingPoint(RGROUP_UAV, psResource->ui32RegisterNumber, &psContext->psShader->sInfo, &psCBuf);
		break;
	case OPERAND_TYPE_THREAD_GROUP_SHARED_MEMORY:
	{
		//dcl_tgsm_structured defines the amount of memory and a stride.
		ASSERT(psResource->ui32RegisterNumber < MAX_GROUPSHARED);
		return &psContext->psShader->sGroupSharedVarType[psResource->ui32RegisterNumber];
	}
	default:
		ASSERT(0);
		break;
	}

	found = GetShaderVarFromOffset(vec4Offset, aui32Swizzle, psCBuf, &psVarType, &index, &rebase);
	ASSERT(found);

	return psVarType;
}


static void TranslateShaderStorageStore(HLSLCrossCompilerContext* psContext, Instruction* psInst)
{
	bstring glsl = *psContext->currentGLSLString;
	ShaderVarType* psVarType = NULL;
	uint32_t ui32DataTypeFlag = TO_FLAG_INTEGER;
	int component;
	int srcComponent = 0;

	Operand* psDest = 0;
	Operand* psDestAddr = 0;
	Operand* psDestByteOff = 0;
	Operand* psSrc = 0;
	int structured = 0;
	int groupshared = 0;

	switch (psInst->eOpcode)
	{
	case OPCODE_STORE_STRUCTURED:
		psDest = &psInst->asOperands[0];
		psDestAddr = &psInst->asOperands[1];
		psDestByteOff = &psInst->asOperands[2];
		psSrc = &psInst->asOperands[3];
		structured = 1;

		break;
	case OPCODE_STORE_RAW:
		psDest = &psInst->asOperands[0];
		psDestByteOff = &psInst->asOperands[1];
		psSrc = &psInst->asOperands[2];
		break;
	}

	for (component = 0; component < 4; component++)
	{
		const char* swizzleString[] = { ".x", ".y", ".z", ".w" };
		ASSERT(psInst->asOperands[0].eSelMode == OPERAND_4_COMPONENT_MASK_MODE);
		if (psInst->asOperands[0].ui32CompMask & (1 << component))
		{
			SHADER_VARIABLE_TYPE eSrcDataType = GetOperandDataType(psContext, psSrc);

			if (structured && psDest->eType != OPERAND_TYPE_THREAD_GROUP_SHARED_MEMORY)
			{
				psVarType = LookupStructuredVar(psContext, psDest, psDestByteOff, component);
			}

			AddIndentation(psContext);

			if (structured && psDest->eType == OPERAND_TYPE_RESOURCE)
			{
				bformata(glsl, "StructuredRes%d", psDest->ui32RegisterNumber);
			}
			else
			{
				TranslateOperand(psContext, psDest, TO_FLAG_DESTINATION | TO_FLAG_NAME_ONLY);
			}
			bformata(glsl, "[");
			if (structured) //Dest address and dest byte offset
			{
				if (psDest->eType == OPERAND_TYPE_THREAD_GROUP_SHARED_MEMORY)
				{
					TranslateOperand(psContext, psDestAddr, TO_FLAG_INTEGER | TO_FLAG_UNSIGNED_INTEGER);
					bformata(glsl, "].value[");
					TranslateOperand(psContext, psDestByteOff, TO_FLAG_INTEGER | TO_FLAG_UNSIGNED_INTEGER);
					bformata(glsl, "/4u ");//bytes to floats
				}
				else
				{
					TranslateOperand(psContext, psDestAddr, TO_FLAG_INTEGER | TO_FLAG_UNSIGNED_INTEGER);
				}
			}
			else
			{
				TranslateOperand(psContext, psDestByteOff, TO_FLAG_INTEGER | TO_FLAG_UNSIGNED_INTEGER);
			}

			//RAW: change component using index offset
			if (!structured || (psDest->eType == OPERAND_TYPE_THREAD_GROUP_SHARED_MEMORY))
			{
				bformata(glsl, " + %d", component);
			}

			bformata(glsl, "]");

			if (structured && psDest->eType != OPERAND_TYPE_THREAD_GROUP_SHARED_MEMORY)
			{
				if (strcmp(psVarType->Name, "$Element") != 0)
				{
					bformata(glsl, ".%s", psVarType->Name);
				}
			}

			if (structured)
			{
				uint32_t flags = TO_FLAG_UNSIGNED_INTEGER;
				if (psVarType)
				{
					if (psVarType->Type == SVT_INT)
					{
						flags = TO_FLAG_INTEGER;
					}
					else if (psVarType->Type == SVT_FLOAT)
					{
						flags = TO_FLAG_NONE;
					}
				}
				//TGSM always uint
				bformata(glsl, " = (");
				if (GetNumSwizzleElements(psSrc) > 1)
					TranslateOperandWithMask(psContext, psSrc, flags, 1 << (srcComponent++));
				else
					TranslateOperandWithMask(psContext, psSrc, flags, OPERAND_4_COMPONENT_MASK_X);

			}
			else
			{
				//Dest type is currently always a uint array.
				bformata(glsl, " = (");
				if (GetNumSwizzleElements(psSrc) > 1)
					TranslateOperandWithMask(psContext, psSrc, TO_FLAG_UNSIGNED_INTEGER, 1 << (srcComponent++));
				else
					TranslateOperandWithMask(psContext, psSrc, TO_FLAG_UNSIGNED_INTEGER, OPERAND_4_COMPONENT_MASK_X);
			}

			//Double takes an extra slot.
			if (psVarType && psVarType->Type == SVT_DOUBLE)
			{
				if (structured && psDest->eType == OPERAND_TYPE_THREAD_GROUP_SHARED_MEMORY)
					bcatcstr(glsl, ")");
				component++;
			}

			bformata(glsl, ");\n");
		}
	}
}
static void TranslateShaderStorageLoad(HLSLCrossCompilerContext* psContext, Instruction* psInst)
{
	bstring glsl = *psContext->currentGLSLString;
	ShaderVarType* psVarType = NULL;
	uint32_t aui32Swizzle[4] = { OPERAND_4_COMPONENT_X };
	uint32_t ui32DataTypeFlag = TO_FLAG_INTEGER;
	int component;
	int destComponent = 0;
	int numParenthesis = 0;
	Operand* psDest = 0;
	Operand* psSrcAddr = 0;
	Operand* psSrcByteOff = 0;
	Operand* psSrc = 0;
	int structured = 0;

	switch (psInst->eOpcode)
	{
	case OPCODE_LD_STRUCTURED:
		psDest = &psInst->asOperands[0];
		psSrcAddr = &psInst->asOperands[1];
		psSrcByteOff = &psInst->asOperands[2];
		psSrc = &psInst->asOperands[3];
		structured = 1;
		break;
	case OPCODE_LD_RAW:
		psDest = &psInst->asOperands[0];
		psSrcByteOff = &psInst->asOperands[1];
		psSrc = &psInst->asOperands[2];
		break;
	}

	if (psInst->eOpcode == OPCODE_LD_RAW)
	{
		int numParenthesis = 0;
		int firstItemAdded = 0;
		uint32_t destCount = GetNumSwizzleElements(psDest);
		uint32_t destMask = GetOperandWriteMask(psDest);
		AddIndentation(psContext);
		AddAssignToDest(psContext, psDest, SVT_UINT, destCount, &numParenthesis);
		if (destCount > 1)
		{
			bformata(glsl, "%s(", GetConstructorForType(SVT_UINT, destCount));
			numParenthesis++;
		}
		for (component = 0; component < 4; component++)
		{
			if (!(destMask & (1 << component)))
				continue;

			if (firstItemAdded)
				bcatcstr(glsl, ", ");
			else
				firstItemAdded = 1;

			bformata(glsl, "RawRes%d[((", psSrc->ui32RegisterNumber);
			TranslateOperand(psContext, psSrcByteOff, TO_FLAG_INTEGER);
			bcatcstr(glsl, ") >> 2)");
			if (psSrc->eSelMode == OPERAND_4_COMPONENT_SWIZZLE_MODE && psSrc->aui32Swizzle[component] != 0)
			{
				bformata(glsl, " + %d", psSrc->aui32Swizzle[component]);
			}
			bcatcstr(glsl, "]");
		}
		AddAssignPrologue(psContext, numParenthesis);
	}
	else
	{
		int numParenthesis = 0;
		int firstItemAdded = 0;
		uint32_t destCount = GetNumSwizzleElements(psDest);
		uint32_t destMask = GetOperandWriteMask(psDest);
		ASSERT(psInst->eOpcode == OPCODE_LD_STRUCTURED);
		AddIndentation(psContext);
		AddAssignToDest(psContext, psDest, SVT_UINT, destCount, &numParenthesis);
		if (destCount > 1)
		{
			bformata(glsl, "%s(", GetConstructorForType(SVT_UINT, destCount));
			numParenthesis++;
		}
		for (component = 0; component < 4; component++)
		{
			ShaderVarType *psVar = NULL;
			int addedBitcast = 0;
			if (!(destMask & (1 << component)))
				continue;

			if (firstItemAdded)
				bcatcstr(glsl, ", ");
			else
				firstItemAdded = 1;

			if (psSrc->eType == OPERAND_TYPE_THREAD_GROUP_SHARED_MEMORY)
			{
				// input already in uints
				TranslateOperand(psContext, psSrc, TO_FLAG_NAME_ONLY);
				bcatcstr(glsl, "[");
				TranslateOperand(psContext, psSrcAddr, TO_FLAG_INTEGER);
				bcatcstr(glsl, "].value[(");
				TranslateOperand(psContext, psSrcByteOff, TO_FLAG_UNSIGNED_INTEGER);
				bformata(glsl, " >> 2u) + %d]", psSrc->eSelMode == OPERAND_4_COMPONENT_SWIZZLE_MODE ? psSrc->aui32Swizzle[component] : component);
			}
			else
			{
				ConstantBuffer *psCBuf = NULL;
				ResourceGroup eGroup = RGROUP_UAV;
				if(OPERAND_TYPE_RESOURCE == psSrc->eType)
				{
					eGroup = RGROUP_TEXTURE;
				}
				psVar = LookupStructuredVar(psContext, psSrc, psSrcByteOff, psSrc->eSelMode == OPERAND_4_COMPONENT_SWIZZLE_MODE ? psSrc->aui32Swizzle[component] : component);
				GetConstantBufferFromBindingPoint(eGroup, psSrc->ui32RegisterNumber, &psContext->psShader->sInfo, &psCBuf);

				if (psVar->Type == SVT_FLOAT)
				{
					bcatcstr(glsl, "floatBitsToUint(");
					addedBitcast = 1;
				}
				else if (psVar->Type == SVT_DOUBLE)
				{
					bcatcstr(glsl, "unpackDouble2x32(");
					addedBitcast = 1;
				}
				if (psSrc->eType == OPERAND_TYPE_UNORDERED_ACCESS_VIEW)
				{
					bformata(glsl, "%s[", psCBuf->Name);
					TranslateOperand(psContext, psSrcAddr, TO_FLAG_INTEGER);
					bcatcstr(glsl, "]");
					if (strcmp(psVar->Name, "$Element") != 0)
					{
						bcatcstr(glsl, ".");
						bcatcstr(glsl, psVar->Name);
					}
				}
				else
				{
					int byteOffset = ((int*)psSrcByteOff->afImmediates)[0] + 4 * component;
					int vec4Offset = byteOffset/16;

					bformata(glsl, "StructuredRes%d[", psSrc->ui32RegisterNumber);
					TranslateOperand(psContext, psSrcAddr, TO_FLAG_INTEGER);
					bcatcstr(glsl, "].");

					//StructuredBuffer<float4x4> WorldTransformData;
					//Becomes cbuf = WorldTransformData and var = $Element.
					if (strcmp(psVar->Name, "$Element") != 0)
					{
						bcatcstr(glsl, psVar->Name);
					}
					else
					{
						bcatcstr(glsl, psCBuf->Name);
					}

					//Select component of matrix.
					if(psVar->Class == SVC_MATRIX_COLUMNS || psVar->Class == SVC_MATRIX_ROWS)
					{
						const char* swizzleString[] = { ".x", ".y", ".z", ".w" };
						bformata(glsl, "[%d]%s", vec4Offset, swizzleString[component]);
					}
				}

				if (addedBitcast)
					bcatcstr(glsl, ")");
				if (psVar->Type == SVT_DOUBLE)
					component++; // doubles take up 2 slots
			}

		}
		AddAssignPrologue(psContext, numParenthesis);

		return;

	}

#if 0

	//(int)GetNumSwizzleElements(&psInst->asOperands[0])
	for (component = 0; component < 4; component++)
	{
		const char* swizzleString[] = { ".x", ".y", ".z", ".w" };
		ASSERT(psDest->eSelMode == OPERAND_4_COMPONENT_MASK_MODE);
		if (psDest->ui32CompMask & (1 << component))
		{
			if (structured && psSrc->eType != OPERAND_TYPE_THREAD_GROUP_SHARED_MEMORY)
			{
				psVarType = LookupStructuredVar(psContext, psSrc, psSrcByteOff, psSrc->aui32Swizzle[component]);
			}

			AddIndentation(psContext);

			aui32Swizzle[0] = psSrc->aui32Swizzle[component];

			TranslateOperand(psContext, psDest, TO_FLAG_DESTINATION);
			if (GetNumSwizzleElements(psDest) > 1)
				bformata(glsl, swizzleString[destComponent++]);

			if (psVarType)
			{
				// TODO completely broken now after AddAssignToDest refactorings.
				AddAssignToDest(psContext, psDest, SVTTypeToFlag(psVarType->Type), GetNumSwizzleElements(psDest), &numParenthesis);
			}
			else
			{
				AddAssignToDest(psContext, psDest, TO_FLAG_NONE, GetNumSwizzleElements(psDest), &numParenthesis);
			}

			if (psSrc->eType == OPERAND_TYPE_RESOURCE)
			{
				if (structured)
					bformata(glsl, "(StructuredRes%d[", psSrc->ui32RegisterNumber);
				else
					bformata(glsl, "(RawRes%d[", psSrc->ui32RegisterNumber);
			}
			else
			{
				bformata(glsl, "(");
				TranslateOperand(psContext, psSrc, TO_FLAG_NAME_ONLY);
				bformata(glsl, "[");
				Translate
			}

			if (structured) //src address and src byte offset
			{
				if (psSrc->eType == OPERAND_TYPE_THREAD_GROUP_SHARED_MEMORY)
				{
					TranslateOperand(psContext, psSrcAddr, TO_FLAG_INTEGER | TO_FLAG_UNSIGNED_INTEGER);
					bformata(glsl, "].value[");
					TranslateOperand(psContext, psSrcByteOff, TO_FLAG_INTEGER | TO_FLAG_UNSIGNED_INTEGER);
					bformata(glsl, "/4u ");//bytes to floats
				}
				else
				{
					TranslateOperand(psContext, psSrcAddr, TO_FLAG_INTEGER | TO_FLAG_UNSIGNED_INTEGER);
				}
			}
			else
			{
				TranslateOperand(psContext, psSrcByteOff, TO_FLAG_INTEGER | TO_FLAG_UNSIGNED_INTEGER);
			}

			//RAW: change component using index offset
			if (!structured || (psSrc->eType == OPERAND_TYPE_THREAD_GROUP_SHARED_MEMORY))
			{
				bformata(glsl, " + %d", psSrc->aui32Swizzle[component]);
			}

			bformata(glsl, "]");
			if (structured && psSrc->eType != OPERAND_TYPE_THREAD_GROUP_SHARED_MEMORY)
			{
				if (strcmp(psVarType->Name, "$Element") != 0)
				{
					bformata(glsl, ".%s", psVarType->Name);
				}

				if (psVarType->Type == SVT_DOUBLE)
				{
					//Double takes an extra slot.
					component++;
				}
			}

			bformata(glsl, ");\n");
		}
	}
#endif
}

void TranslateAtomicMemOp(HLSLCrossCompilerContext* psContext, Instruction* psInst)
{
	bstring glsl = *psContext->currentGLSLString;
	int numParenthesis = 0;
	ShaderVarType* psVarType = NULL;
	uint32_t ui32DataTypeFlag = TO_FLAG_INTEGER;
	const char* func = "";
	Operand* dest = 0;
	Operand* previousValue = 0;
	Operand* destAddr = 0;
	Operand* src = 0;
	Operand* compare = 0;
	int destAddressIn32bits = 0;

	switch (psInst->eOpcode)
	{
	case OPCODE_IMM_ATOMIC_IADD:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//IMM_ATOMIC_IADD\n");
#endif     
		func = "atomicAdd";
		previousValue = &psInst->asOperands[0];
		dest = &psInst->asOperands[1];
		destAddr = &psInst->asOperands[2];
		src = &psInst->asOperands[3];
		break;
	}
	case OPCODE_ATOMIC_IADD:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//ATOMIC_IADD\n");
#endif  
		func = "atomicAdd";
		dest = &psInst->asOperands[0];
		destAddr = &psInst->asOperands[1];
		src = &psInst->asOperands[2];
		break;
	}
	case OPCODE_IMM_ATOMIC_AND:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//IMM_ATOMIC_AND\n");
#endif     
		func = "atomicAnd";
		previousValue = &psInst->asOperands[0];
		dest = &psInst->asOperands[1];
		destAddr = &psInst->asOperands[2];
		src = &psInst->asOperands[3];
		break;
	}
	case OPCODE_ATOMIC_AND:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//ATOMIC_AND\n");
#endif  
		func = "atomicAnd";
		dest = &psInst->asOperands[0];
		destAddr = &psInst->asOperands[1];
		src = &psInst->asOperands[2];
		break;
	}
	case OPCODE_IMM_ATOMIC_OR:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//IMM_ATOMIC_OR\n");
#endif     
		func = "atomicOr";
		previousValue = &psInst->asOperands[0];
		dest = &psInst->asOperands[1];
		destAddr = &psInst->asOperands[2];
		src = &psInst->asOperands[3];
		break;
	}
	case OPCODE_ATOMIC_OR:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//ATOMIC_OR\n");
#endif  
		func = "atomicOr";
		dest = &psInst->asOperands[0];
		destAddr = &psInst->asOperands[1];
		src = &psInst->asOperands[2];
		break;
	}
	case OPCODE_IMM_ATOMIC_XOR:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//IMM_ATOMIC_XOR\n");
#endif     
		func = "atomicXor";
		previousValue = &psInst->asOperands[0];
		dest = &psInst->asOperands[1];
		destAddr = &psInst->asOperands[2];
		src = &psInst->asOperands[3];
		break;
	}
	case OPCODE_ATOMIC_XOR:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//ATOMIC_XOR\n");
#endif  
		func = "atomicXor";
		dest = &psInst->asOperands[0];
		destAddr = &psInst->asOperands[1];
		src = &psInst->asOperands[2];
		break;
	}

	case OPCODE_IMM_ATOMIC_EXCH:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//IMM_ATOMIC_EXCH\n");
#endif     
		func = "atomicExchange";
		previousValue = &psInst->asOperands[0];
		dest = &psInst->asOperands[1];
		destAddr = &psInst->asOperands[2];
		src = &psInst->asOperands[3];
		break;
	}
	case OPCODE_IMM_ATOMIC_CMP_EXCH:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//IMM_ATOMIC_CMP_EXC\n");
#endif     
		func = "atomicCompSwap";
		previousValue = &psInst->asOperands[0];
		dest = &psInst->asOperands[1];
		destAddr = &psInst->asOperands[2];
		compare = &psInst->asOperands[3];
		src = &psInst->asOperands[4];
		break;
	}
	case OPCODE_ATOMIC_CMP_STORE:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//ATOMIC_CMP_STORE\n");
#endif     
		func = "atomicCompSwap";
		previousValue = 0;
		dest = &psInst->asOperands[0];
		destAddr = &psInst->asOperands[1];
		compare = &psInst->asOperands[2];
		src = &psInst->asOperands[3];
		break;
	}
	case OPCODE_IMM_ATOMIC_UMIN:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//IMM_ATOMIC_UMIN\n");
#endif     
		func = "atomicMin";
		previousValue = &psInst->asOperands[0];
		dest = &psInst->asOperands[1];
		destAddr = &psInst->asOperands[2];
		src = &psInst->asOperands[3];
		break;
	}
	case OPCODE_ATOMIC_UMIN:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//ATOMIC_UMIN\n");
#endif  
		func = "atomicMin";
		dest = &psInst->asOperands[0];
		destAddr = &psInst->asOperands[1];
		src = &psInst->asOperands[2];
		break;
	}
	case OPCODE_IMM_ATOMIC_IMIN:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//IMM_ATOMIC_IMIN\n");
#endif     
		func = "atomicMin";
		previousValue = &psInst->asOperands[0];
		dest = &psInst->asOperands[1];
		destAddr = &psInst->asOperands[2];
		src = &psInst->asOperands[3];
		break;
	}
	case OPCODE_ATOMIC_IMIN:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//ATOMIC_IMIN\n");
#endif  
		func = "atomicMin";
		dest = &psInst->asOperands[0];
		destAddr = &psInst->asOperands[1];
		src = &psInst->asOperands[2];
		break;
	}
	case OPCODE_IMM_ATOMIC_UMAX:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//IMM_ATOMIC_UMAX\n");
#endif     
		func = "atomicMax";
		previousValue = &psInst->asOperands[0];
		dest = &psInst->asOperands[1];
		destAddr = &psInst->asOperands[2];
		src = &psInst->asOperands[3];
		break;
	}
	case OPCODE_ATOMIC_UMAX:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//ATOMIC_UMAX\n");
#endif  
		func = "atomicMax";
		dest = &psInst->asOperands[0];
		destAddr = &psInst->asOperands[1];
		src = &psInst->asOperands[2];
		break;
	}
	case OPCODE_IMM_ATOMIC_IMAX:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//IMM_ATOMIC_IMAX\n");
#endif     
		func = "atomicMax";
		previousValue = &psInst->asOperands[0];
		dest = &psInst->asOperands[1];
		destAddr = &psInst->asOperands[2];
		src = &psInst->asOperands[3];
		break;
	}
	case OPCODE_ATOMIC_IMAX:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//ATOMIC_IMAX\n");
#endif  
		func = "atomicMax";
		dest = &psInst->asOperands[0];
		destAddr = &psInst->asOperands[1];
		src = &psInst->asOperands[2];
		break;
	}
	}

	AddIndentation(psContext);

	//LookupStructuredVar expectes byte address so it can handle ld_structured et al.
	//atomic_imin address is in units of 32-bit
	destAddressIn32bits = ((int*)destAddr->afImmediates)[0];
	((int*)destAddr->afImmediates)[0] *= 4;
	psVarType = LookupStructuredVar(psContext, dest, destAddr, 0);
	if (psVarType->Type == SVT_UINT)
	{
		ui32DataTypeFlag = TO_FLAG_UNSIGNED_INTEGER | TO_AUTO_BITCAST_TO_UINT;
	}
	else
	{
		ui32DataTypeFlag = TO_FLAG_INTEGER | TO_AUTO_BITCAST_TO_INT;
	}

	if (previousValue)
	{
		AddAssignToDest(psContext, previousValue, psVarType->Type, 1, &numParenthesis);
	}
	bcatcstr(glsl, func);
	bformata(glsl, "(");
	ResourceName(glsl, psContext, RGROUP_UAV, dest->ui32RegisterNumber, 0);
	bformata(glsl, "[%d]", destAddressIn32bits);
	if (strcmp(psVarType->Name, "$Element") != 0)
	{
		bformata(glsl, ".%s", psVarType->Name);
	}

	bcatcstr(glsl, ", ");

	if (compare)
	{
		TranslateOperand(psContext, compare, ui32DataTypeFlag);
		bcatcstr(glsl, ", ");
	}

	TranslateOperand(psContext, src, ui32DataTypeFlag);
	bcatcstr(glsl, ")");
	if (previousValue)
	{
		AddAssignPrologue(psContext, numParenthesis);
	}
	else
		bcatcstr(glsl, ";\n");
}

static void TranslateConditional(HLSLCrossCompilerContext* psContext,
	Instruction* psInst,
	bstring glsl)
{
	const char* statement = "";
	if (psInst->eOpcode == OPCODE_BREAKC)
	{
		statement = "break";
	}
	else if (psInst->eOpcode == OPCODE_CONTINUEC)
	{
		statement = "continue";
	}
	else if (psInst->eOpcode == OPCODE_RETC)
	{
		statement = "return";
	}

	if (psContext->psShader->ui32MajorVersion < 4)
	{
		bcatcstr(glsl, "if(");

		TranslateOperand(psContext, &psInst->asOperands[0], SVTTypeToFlag(GetOperandDataType(psContext, &psInst->asOperands[0])));
		switch (psInst->eDX9TestType)
		{
		case D3DSPC_GT:
		{
			bcatcstr(glsl, " > ");
			break;
		}
		case D3DSPC_EQ:
		{
			bcatcstr(glsl, " == ");
			break;
		}
		case D3DSPC_GE:
		{
			bcatcstr(glsl, " >= ");
			break;
		}
		case D3DSPC_LT:
		{
			bcatcstr(glsl, " < ");
			break;
		}
		case D3DSPC_NE:
		{
			bcatcstr(glsl, " != ");
			break;
		}
		case D3DSPC_LE:
		{
			bcatcstr(glsl, " <= ");
			break;
		}
		case D3DSPC_BOOLEAN:
		{
			bcatcstr(glsl, " != 0");
			break;
		}
		default:
		{
			break;
		}
		}

		if (psInst->eDX9TestType != D3DSPC_BOOLEAN)
		{
			TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_NONE);
		}

		if (psInst->eOpcode != OPCODE_IF)
		{
			bformata(glsl, "){ %s; }\n", statement);
		}
		else
		{
			bcatcstr(glsl, "){\n");
		}
	}
	else
	{
		if (psInst->eBooleanTestType == INSTRUCTION_TEST_ZERO)
		{
			bcatcstr(glsl, "if((");
			TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_UNSIGNED_INTEGER);

			if (psInst->eOpcode != OPCODE_IF)
			{
				bformata(glsl, ")==0u){%s;}\n", statement);
			}
			else
			{
				bcatcstr(glsl, ")==0u){\n");
			}
		}
		else
		{
			ASSERT(psInst->eBooleanTestType == INSTRUCTION_TEST_NONZERO);
			bcatcstr(glsl, "if((");
			TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_UNSIGNED_INTEGER);

			if (psInst->eOpcode != OPCODE_IF)
			{
				bformata(glsl, ")!=0u){%s;}\n", statement);
			}
			else
			{
				bcatcstr(glsl, ")!=0u){\n");
			}
		}
	}
}

// Returns the "more important" type of a and b, currently int < uint < float
static SHADER_VARIABLE_TYPE SelectHigherType(SHADER_VARIABLE_TYPE a, SHADER_VARIABLE_TYPE b)
{
	if (a == SVT_FLOAT || b == SVT_FLOAT)
		return SVT_FLOAT;
	// Apart from floats, the enum values are fairly well-ordered, use that directly.
	return a > b ? a : b;
}

// Helper function to set the vector type of 1 or more components in a vector
// If the existing values (that we're writing to) are all SVT_VOID, just upgrade the value and we're done
// Otherwise, set all the components in the vector that currently are set to that same value OR are now being written to
// to the "highest" type value (ordering int->uint->float)
static void SetVectorType(SHADER_VARIABLE_TYPE *aeTempVecType, uint32_t regBaseIndex, uint32_t componentMask, SHADER_VARIABLE_TYPE eType)
{
	int existingTypesFound = 0;
	int i = 0;
	for (i = 0; i < 4; i++)
	{
		if (componentMask & (1 << i))
		{
			if (aeTempVecType[regBaseIndex + i] != SVT_VOID)
			{
				existingTypesFound = 1;
				break;
			}
		}
	}

	if (existingTypesFound != 0)
	{
		// Expand the mask to include all components that are used, also upgrade type
		for (i = 0; i < 4; i++)
		{
			if (aeTempVecType[regBaseIndex + i] != SVT_VOID)
			{
				componentMask |= (1 << i);
				eType = SelectHigherType(eType, aeTempVecType[regBaseIndex + i]);
			}
		}
	}

	// Now componentMask contains the components we actually need to update and eType may have been changed to something else.
	// Write the results
	for (i = 0; i < 4; i++)
	{
		if (componentMask & (1 << i))
		{
			aeTempVecType[regBaseIndex + i] = eType;
		}
	}

}

static void MarkOperandAs(Operand *psOperand, SHADER_VARIABLE_TYPE eType, SHADER_VARIABLE_TYPE *aeTempVecType)
{
	if (psOperand->eType == OPERAND_TYPE_INDEXABLE_TEMP || psOperand->eType == OPERAND_TYPE_TEMP)
	{
		const uint32_t ui32RegIndex = psOperand->ui32RegisterNumber * 4;

		if (psOperand->eSelMode == OPERAND_4_COMPONENT_SELECT_1_MODE)
		{
			SetVectorType(aeTempVecType, ui32RegIndex, 1 << psOperand->aui32Swizzle[0], eType);
		}
		else if (psOperand->eSelMode == OPERAND_4_COMPONENT_SWIZZLE_MODE)
		{
			// 0xf == all components, swizzle order doesn't matter.
			SetVectorType(aeTempVecType, ui32RegIndex, 0xf, eType);
		}
		else if (psOperand->eSelMode == OPERAND_4_COMPONENT_MASK_MODE)
		{
			uint32_t ui32CompMask = psOperand->ui32CompMask;
			if (!psOperand->ui32CompMask)
			{
				ui32CompMask = OPERAND_4_COMPONENT_MASK_ALL;
			}

			SetVectorType(aeTempVecType, ui32RegIndex, ui32CompMask, eType);
		}
	}
}

static void MarkAllOperandsAs(Instruction* psInst, SHADER_VARIABLE_TYPE eType, SHADER_VARIABLE_TYPE *aeTempVecType)
{
	uint32_t i = 0;
	for (i = 0; i < psInst->ui32NumOperands; i++)
	{
		MarkOperandAs(&psInst->asOperands[i], eType, aeTempVecType);
	}
}

static void WriteOperandTypes(Operand *psOperand, const SHADER_VARIABLE_TYPE *aeTempVecType)
{
	const uint32_t ui32RegIndex = psOperand->ui32RegisterNumber * 4;

	if (psOperand->eType != OPERAND_TYPE_TEMP)
		return;

	if (psOperand->eSelMode == OPERAND_4_COMPONENT_SELECT_1_MODE)
	{
		psOperand->aeDataType[psOperand->aui32Swizzle[0]] = aeTempVecType[ui32RegIndex + psOperand->aui32Swizzle[0]];
	}
	else if (psOperand->eSelMode == OPERAND_4_COMPONENT_SWIZZLE_MODE)
	{
		if (psOperand->ui32Swizzle == (NO_SWIZZLE))
		{
			psOperand->aeDataType[0] = aeTempVecType[ui32RegIndex];
			psOperand->aeDataType[1] = aeTempVecType[ui32RegIndex + 1];
			psOperand->aeDataType[2] = aeTempVecType[ui32RegIndex + 2];
			psOperand->aeDataType[3] = aeTempVecType[ui32RegIndex + 3];
		}
		else
		{
			psOperand->aeDataType[psOperand->aui32Swizzle[0]] = aeTempVecType[ui32RegIndex + psOperand->aui32Swizzle[0]];
			psOperand->aeDataType[psOperand->aui32Swizzle[1]] = aeTempVecType[ui32RegIndex + psOperand->aui32Swizzle[1]];
			psOperand->aeDataType[psOperand->aui32Swizzle[2]] = aeTempVecType[ui32RegIndex + psOperand->aui32Swizzle[2]];
			psOperand->aeDataType[psOperand->aui32Swizzle[3]] = aeTempVecType[ui32RegIndex + psOperand->aui32Swizzle[3]];
		}
	}
	else if (psOperand->eSelMode == OPERAND_4_COMPONENT_MASK_MODE)
	{
		int c = 0;
		uint32_t ui32CompMask = psOperand->ui32CompMask;
		if (!psOperand->ui32CompMask)
		{
			ui32CompMask = OPERAND_4_COMPONENT_MASK_ALL;
		}

		for (; c < 4; ++c)
		{
			if (ui32CompMask & (1 << c))
			{
				psOperand->aeDataType[c] = aeTempVecType[ui32RegIndex + c];
			}
		}
	}
}

// Mark scalars from CBs. TODO: Do we need to do the same for vec2/3's as well? There may be swizzles involved which make it vec4 or something else again.
static void SetCBOperandComponents(HLSLCrossCompilerContext *psContext, Operand *psOperand)
{
	ConstantBuffer* psCBuf = NULL;
	ShaderVarType* psVarType = NULL;
	int32_t index = -1;
	int rebase = 0;

	if (psOperand->eType != OPERAND_TYPE_CONSTANT_BUFFER)
		return;

	GetConstantBufferFromBindingPoint(RGROUP_CBUFFER, psOperand->aui32ArraySizes[0], &psContext->psShader->sInfo, &psCBuf);
	GetShaderVarFromOffset(psOperand->aui32ArraySizes[1], psOperand->aui32Swizzle, psCBuf, &psVarType, &index, &rebase);

	if (psVarType->Class == SVC_SCALAR)
		psOperand->iNumComponents = 1;

}


void SetDataTypes(HLSLCrossCompilerContext* psContext, Instruction* psInst, const int32_t i32InstCount)
{
	int32_t i;
	Instruction *psFirstInst = psInst;

	SHADER_VARIABLE_TYPE aeTempVecType[MAX_TEMP_VEC4 * 4];

	if (psContext->psShader->ui32MajorVersion <= 3)
	{
		for (i = 0; i < MAX_TEMP_VEC4 * 4; ++i)
		{
			aeTempVecType[i] = SVT_FLOAT;
		}
	}
	else
	{
		// Start with void, then move up the chain void->int->uint->float
		for (i = 0; i < MAX_TEMP_VEC4 * 4; ++i)
		{
			aeTempVecType[i] = SVT_VOID;
		}
	}

//	if (psContext->psShader->ui32MajorVersion <= 3)
	{
		// First pass, do analysis: deduce the data type based on opcodes, fill out aeTempVecType table
		// Only ever to int->float promotion (or int->uint), never the other way around
		for (i = 0; i < i32InstCount; ++i, psInst++)
		{
			int k = 0;
			if (psInst->ui32NumOperands == 0)
				continue;

			switch (psInst->eOpcode)
			{
				// All float-only ops
			case OPCODE_ADD:
			case OPCODE_DERIV_RTX:
			case OPCODE_DERIV_RTY:
			case OPCODE_DIV:
			case OPCODE_DP2:
			case OPCODE_DP3:
			case OPCODE_DP4:
			case OPCODE_EQ:
			case OPCODE_EXP:
			case OPCODE_FRC:
			case OPCODE_LOG:
			case OPCODE_MAD:
			case OPCODE_MIN:
			case OPCODE_MAX:
			case OPCODE_MUL:
			case OPCODE_NE:
			case OPCODE_ROUND_NE:
			case OPCODE_ROUND_NI:
			case OPCODE_ROUND_PI:
			case OPCODE_ROUND_Z:
			case OPCODE_RSQ:
			case OPCODE_SAMPLE:
			case OPCODE_SAMPLE_C:
			case OPCODE_SAMPLE_C_LZ:
			case OPCODE_SAMPLE_L:
			case OPCODE_SAMPLE_D:
			case OPCODE_SAMPLE_B:
			case OPCODE_SQRT:
			case OPCODE_SINCOS:
			case OPCODE_LOD:
			case OPCODE_GATHER4:

			case OPCODE_DERIV_RTX_COARSE:
			case OPCODE_DERIV_RTX_FINE:
			case OPCODE_DERIV_RTY_COARSE:
			case OPCODE_DERIV_RTY_FINE:
			case OPCODE_GATHER4_C:
			case OPCODE_GATHER4_PO:
			case OPCODE_GATHER4_PO_C:
			case OPCODE_RCP:

				MarkAllOperandsAs(psInst, SVT_FLOAT, aeTempVecType);
				break;

				// Int-only ops, no need to do anything
			case OPCODE_AND:
			case OPCODE_BREAKC:
			case OPCODE_CALLC:
			case OPCODE_CONTINUEC:
			case OPCODE_IADD:
			case OPCODE_IEQ:
			case OPCODE_IGE:
			case OPCODE_ILT:
			case OPCODE_IMAD:
			case OPCODE_IMAX:
			case OPCODE_IMIN:
			case OPCODE_IMUL:
			case OPCODE_INE:
			case OPCODE_INEG:
			case OPCODE_ISHL:
			case OPCODE_ISHR:
			case OPCODE_IF:
			case OPCODE_NOT:
			case OPCODE_OR:
			case OPCODE_RETC:
			case OPCODE_XOR:
			case OPCODE_BUFINFO:
			case OPCODE_COUNTBITS:
			case OPCODE_FIRSTBIT_HI:
			case OPCODE_FIRSTBIT_LO:
			case OPCODE_FIRSTBIT_SHI:
			case OPCODE_UBFE:
			case OPCODE_IBFE:
			case OPCODE_BFI:
			case OPCODE_BFREV:
			case OPCODE_ATOMIC_AND:
			case OPCODE_ATOMIC_OR:
			case OPCODE_ATOMIC_XOR:
			case OPCODE_ATOMIC_CMP_STORE:
			case OPCODE_ATOMIC_IADD:
			case OPCODE_ATOMIC_IMAX:
			case OPCODE_ATOMIC_IMIN:
			case OPCODE_ATOMIC_UMAX:
			case OPCODE_ATOMIC_UMIN:
			case OPCODE_IMM_ATOMIC_ALLOC:
			case OPCODE_IMM_ATOMIC_CONSUME:
			case OPCODE_IMM_ATOMIC_IADD:
			case OPCODE_IMM_ATOMIC_AND:
			case OPCODE_IMM_ATOMIC_OR:
			case OPCODE_IMM_ATOMIC_XOR:
			case OPCODE_IMM_ATOMIC_EXCH:
			case OPCODE_IMM_ATOMIC_CMP_EXCH:
			case OPCODE_IMM_ATOMIC_IMAX:
			case OPCODE_IMM_ATOMIC_IMIN:
			case OPCODE_IMM_ATOMIC_UMAX:
			case OPCODE_IMM_ATOMIC_UMIN:
			case OPCODE_MOV:
			case OPCODE_MOVC:
			case OPCODE_SWAPC:
				MarkAllOperandsAs(psInst, SVT_INT, aeTempVecType);
				break;
				// uint ops
			case OPCODE_UDIV:
			case OPCODE_ULT:
			case OPCODE_UGE:
			case OPCODE_UMUL:
			case OPCODE_UMAD:
			case OPCODE_UMAX:
			case OPCODE_UMIN:
			case OPCODE_USHR:
			case OPCODE_UADDC:
			case OPCODE_USUBB:
				MarkAllOperandsAs(psInst, SVT_UINT, aeTempVecType);
				break;

				// Need special handling
			case OPCODE_FTOI:
			case OPCODE_FTOU:
				MarkOperandAs(&psInst->asOperands[0], psInst->eOpcode == OPCODE_FTOI ? SVT_INT : SVT_UINT, aeTempVecType);
				MarkOperandAs(&psInst->asOperands[1], SVT_FLOAT, aeTempVecType);
				break;

			case OPCODE_GE:
			case OPCODE_LT:
				MarkOperandAs(&psInst->asOperands[0], SVT_UINT, aeTempVecType);
				MarkOperandAs(&psInst->asOperands[1], SVT_FLOAT, aeTempVecType);
				MarkOperandAs(&psInst->asOperands[2], SVT_FLOAT, aeTempVecType);
				break;

			case OPCODE_ITOF:
			case OPCODE_UTOF:
				MarkOperandAs(&psInst->asOperands[0], SVT_FLOAT, aeTempVecType);
				MarkOperandAs(&psInst->asOperands[1], psInst->eOpcode == OPCODE_ITOF ? SVT_INT : SVT_UINT, aeTempVecType);
				break;

			case OPCODE_LD:
			case OPCODE_LD_MS:
				// TODO: Would need to know the sampler return type
				MarkOperandAs(&psInst->asOperands[0], SVT_FLOAT, aeTempVecType);
				break;


			case OPCODE_RESINFO:
			{
				if (psInst->eResInfoReturnType != RESINFO_INSTRUCTION_RETURN_UINT)
					MarkAllOperandsAs(psInst, SVT_FLOAT, aeTempVecType);
				break;
			}

			case OPCODE_SAMPLE_INFO:
				// TODO decode the _uint flag
				MarkOperandAs(&psInst->asOperands[0], SVT_FLOAT, aeTempVecType);
				break;

			case OPCODE_SAMPLE_POS:
				MarkOperandAs(&psInst->asOperands[0], SVT_FLOAT, aeTempVecType);
				break;


			case OPCODE_LD_UAV_TYPED:
			case OPCODE_STORE_UAV_TYPED:
			case OPCODE_LD_RAW:
			case OPCODE_STORE_RAW:
			case OPCODE_LD_STRUCTURED:
			case OPCODE_STORE_STRUCTURED:
				MarkOperandAs(&psInst->asOperands[0], SVT_INT, aeTempVecType);
				break;

			case OPCODE_F32TOF16:
			case OPCODE_F16TOF32:
				// TODO
				break;



				// No-operands, should never get here anyway
				/*				case OPCODE_BREAK:
								case OPCODE_CALL:
								case OPCODE_CASE:
								case OPCODE_CONTINUE:
								case OPCODE_CUT:
								case OPCODE_DEFAULT:
								case OPCODE_DISCARD:
								case OPCODE_ELSE:
								case OPCODE_EMIT:
								case OPCODE_EMITTHENCUT:
								case OPCODE_ENDIF:
								case OPCODE_ENDLOOP:
								case OPCODE_ENDSWITCH:

								case OPCODE_LABEL:
								case OPCODE_LOOP:
								case OPCODE_CUSTOMDATA:
								case OPCODE_NOP:
								case OPCODE_RET:
								case OPCODE_SWITCH:
								case OPCODE_DCL_RESOURCE: // DCL* opcodes have
								case OPCODE_DCL_CONSTANT_BUFFER: // custom operand formats.
								case OPCODE_DCL_SAMPLER:
								case OPCODE_DCL_INDEX_RANGE:
								case OPCODE_DCL_GS_OUTPUT_PRIMITIVE_TOPOLOGY:
								case OPCODE_DCL_GS_INPUT_PRIMITIVE:
								case OPCODE_DCL_MAX_OUTPUT_VERTEX_COUNT:
								case OPCODE_DCL_INPUT:
								case OPCODE_DCL_INPUT_SGV:
								case OPCODE_DCL_INPUT_SIV:
								case OPCODE_DCL_INPUT_PS:
								case OPCODE_DCL_INPUT_PS_SGV:
								case OPCODE_DCL_INPUT_PS_SIV:
								case OPCODE_DCL_OUTPUT:
								case OPCODE_DCL_OUTPUT_SGV:
								case OPCODE_DCL_OUTPUT_SIV:
								case OPCODE_DCL_TEMPS:
								case OPCODE_DCL_INDEXABLE_TEMP:
								case OPCODE_DCL_GLOBAL_FLAGS:


								case OPCODE_HS_DECLS: // token marks beginning of HS sub-shader
								case OPCODE_HS_CONTROL_POINT_PHASE: // token marks beginning of HS sub-shader
								case OPCODE_HS_FORK_PHASE: // token marks beginning of HS sub-shader
								case OPCODE_HS_JOIN_PHASE: // token marks beginning of HS sub-shader

								case OPCODE_EMIT_STREAM:
								case OPCODE_CUT_STREAM:
								case OPCODE_EMITTHENCUT_STREAM:
								case OPCODE_INTERFACE_CALL:


								case OPCODE_DCL_STREAM:
								case OPCODE_DCL_FUNCTION_BODY:
								case OPCODE_DCL_FUNCTION_TABLE:
								case OPCODE_DCL_INTERFACE:

								case OPCODE_DCL_INPUT_CONTROL_POINT_COUNT:
								case OPCODE_DCL_OUTPUT_CONTROL_POINT_COUNT:
								case OPCODE_DCL_TESS_DOMAIN:
								case OPCODE_DCL_TESS_PARTITIONING:
								case OPCODE_DCL_TESS_OUTPUT_PRIMITIVE:
								case OPCODE_DCL_HS_MAX_TESSFACTOR:
								case OPCODE_DCL_HS_FORK_PHASE_INSTANCE_COUNT:
								case OPCODE_DCL_HS_JOIN_PHASE_INSTANCE_COUNT:

								case OPCODE_DCL_THREAD_GROUP:
								case OPCODE_DCL_UNORDERED_ACCESS_VIEW_TYPED:
								case OPCODE_DCL_UNORDERED_ACCESS_VIEW_RAW:
								case OPCODE_DCL_UNORDERED_ACCESS_VIEW_STRUCTURED:
								case OPCODE_DCL_THREAD_GROUP_SHARED_MEMORY_RAW:
								case OPCODE_DCL_THREAD_GROUP_SHARED_MEMORY_STRUCTURED:
								case OPCODE_DCL_RESOURCE_RAW:
								case OPCODE_DCL_RESOURCE_STRUCTURED:
								case OPCODE_SYNC:

								// TODO
								case OPCODE_DADD:
								case OPCODE_DMAX:
								case OPCODE_DMIN:
								case OPCODE_DMUL:
								case OPCODE_DEQ:
								case OPCODE_DGE:
								case OPCODE_DLT:
								case OPCODE_DNE:
								case OPCODE_DMOV:
								case OPCODE_DMOVC:
								case OPCODE_DTOF:
								case OPCODE_FTOD:

								case OPCODE_EVAL_SNAPPED:
								case OPCODE_EVAL_SAMPLE_INDEX:
								case OPCODE_EVAL_CENTROID:

								case OPCODE_DCL_GS_INSTANCE_COUNT:

								case OPCODE_ABORT:
								case OPCODE_DEBUG_BREAK:*/

			default:
				break;
			}
		}
	}

	// Fill the rest of aeTempVecType, just in case.
	for (i = 0; i < MAX_TEMP_VEC4 * 4; i++)
	{
		if (aeTempVecType[i] == SVT_VOID)
			aeTempVecType[i] = SVT_INT;
	}

	// Now the aeTempVecType table has been filled with (mostly) valid data, write it back to all operands
	psInst = psFirstInst;
	for (i = 0; i < i32InstCount; ++i, psInst++)
	{
		int k = 0;

		if (psInst->ui32NumOperands == 0)
			continue;

		//Preserve the current type on dest array index
		if (psInst->asOperands[0].eType == OPERAND_TYPE_INDEXABLE_TEMP)
		{
			Operand* psSubOperand = psInst->asOperands[0].psSubOperand[1];
			if (psSubOperand != 0)
			{
				WriteOperandTypes(psSubOperand, aeTempVecType);
			}
		}
		if (psInst->asOperands[0].eType == OPERAND_TYPE_CONSTANT_BUFFER)
			SetCBOperandComponents(psContext, &psInst->asOperands[0]);

		//Preserve the current type on sources.
		for (k = psInst->ui32NumOperands - 1; k >= (int)psInst->ui32FirstSrc; --k)
		{
			int32_t subOperand;
			Operand* psOperand = &psInst->asOperands[k];

			WriteOperandTypes(psOperand, aeTempVecType);
			if (psOperand->eType == OPERAND_TYPE_CONSTANT_BUFFER)
				SetCBOperandComponents(psContext, psOperand);

			for (subOperand = 0; subOperand < MAX_SUB_OPERANDS; subOperand++)
			{
				if (psOperand->psSubOperand[subOperand] != 0)
				{
					Operand* psSubOperand = psOperand->psSubOperand[subOperand];
					WriteOperandTypes(psSubOperand, aeTempVecType);
					if (psSubOperand->eType == OPERAND_TYPE_CONSTANT_BUFFER)
						SetCBOperandComponents(psContext, psSubOperand);
				}
			}

			//Set immediates
			if (IsIntegerImmediateOpcode(psInst->eOpcode))
			{
				if (psOperand->eType == OPERAND_TYPE_IMMEDIATE32)
				{
					psOperand->iIntegerImmediate = 1;
				}
			}
		}

		//Process the destination last in order to handle instructions
		//where the destination register is also used as a source.
		for (k = 0; k < (int)psInst->ui32FirstSrc; ++k)
		{
			Operand* psOperand = &psInst->asOperands[k];
			WriteOperandTypes(psOperand, aeTempVecType);
		}
	}
}

void TranslateInstruction(HLSLCrossCompilerContext* psContext, Instruction* psInst, Instruction* psNextInst)
{
	bstring glsl = *psContext->currentGLSLString;
	int numParenthesis = 0;

#ifdef _DEBUG
	AddIndentation(psContext);
	bformata(glsl, "//Instruction %d\n", psInst->id);
#if 0
	if(psInst->id == 73)
	{
		ASSERT(1); //Set breakpoint here to debug an instruction from its ID.
	}
#endif
#endif

	switch (psInst->eOpcode)
	{
	case OPCODE_FTOI:
	case OPCODE_FTOU:
	{
		uint32_t dstCount = GetNumSwizzleElements(&psInst->asOperands[0]);
		uint32_t srcCount = GetNumSwizzleElements(&psInst->asOperands[1]);
		uint32_t ui32DstFlags = TO_FLAG_DESTINATION;
		const SHADER_VARIABLE_TYPE eSrcType = GetOperandDataType(psContext, &psInst->asOperands[1]);
		const SHADER_VARIABLE_TYPE eDestType = GetOperandDataType(psContext, &psInst->asOperands[0]);

#ifdef _DEBUG
		AddIndentation(psContext);
		if (psInst->eOpcode == OPCODE_FTOU)
			bcatcstr(glsl, "//FTOU\n");
		else
			bcatcstr(glsl, "//FTOI\n");
#endif

		AddIndentation(psContext);

		AddAssignToDest(psContext, &psInst->asOperands[0], psInst->eOpcode == OPCODE_FTOU ? SVT_UINT : SVT_INT, srcCount, &numParenthesis);
		bcatcstr(glsl, GetConstructorForType(psInst->eOpcode == OPCODE_FTOU ? SVT_UINT : SVT_INT, srcCount == dstCount ? dstCount : 4));
		bcatcstr(glsl, "("); // 1
		TranslateOperand(psContext, &psInst->asOperands[1], TO_AUTO_BITCAST_TO_FLOAT);
		bcatcstr(glsl, ")"); // 1
		// Add destination writemask if the component counts do not match
		if (srcCount != dstCount)
			AddSwizzleUsingElementCount(psContext, dstCount);
		AddAssignPrologue(psContext, numParenthesis);
		break;
	}

	case OPCODE_MOV:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//MOV\n");
#endif
		AddIndentation(psContext);
		AddMOVBinaryOp(psContext, &psInst->asOperands[0], &psInst->asOperands[1]);
		break;
	}
	case OPCODE_ITOF://signed to float
	case OPCODE_UTOF://unsigned to float
	{
		const SHADER_VARIABLE_TYPE eDestType = GetOperandDataType(psContext, &psInst->asOperands[0]);
		const SHADER_VARIABLE_TYPE eSrcType = GetOperandDataType(psContext, &psInst->asOperands[1]);
		uint32_t dstCount = GetNumSwizzleElements(&psInst->asOperands[0]);
		uint32_t srcCount = GetNumSwizzleElements(&psInst->asOperands[1]);

#ifdef _DEBUG
		AddIndentation(psContext);
		if (psInst->eOpcode == OPCODE_ITOF)
		{
			bcatcstr(glsl, "//ITOF\n");
		}
		else
		{
			bcatcstr(glsl, "//UTOF\n");
		}
#endif
		AddIndentation(psContext);
		AddAssignToDest(psContext, &psInst->asOperands[0], SVT_FLOAT, srcCount, &numParenthesis);
		bcatcstr(glsl, GetConstructorForType(SVT_FLOAT, srcCount == dstCount ? dstCount : 4));
		bcatcstr(glsl, "("); // 1
		TranslateOperand(psContext, &psInst->asOperands[1], psInst->eOpcode == OPCODE_UTOF ? TO_AUTO_BITCAST_TO_UINT : TO_AUTO_BITCAST_TO_INT);
		bcatcstr(glsl, ")"); // 1
		// Add destination writemask if the component counts do not match
		if (srcCount != dstCount)
			AddSwizzleUsingElementCount(psContext, dstCount);
		AddAssignPrologue(psContext, numParenthesis);
		break;
	}
	case OPCODE_MAD:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//MAD\n");
#endif
		CallTernaryOp(psContext, "*", "+", psInst, 0, 1, 2, 3, TO_FLAG_NONE);
		break;
	}
	case OPCODE_IMAD:
	{
		uint32_t ui32Flags = TO_FLAG_INTEGER;
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//IMAD\n");
#endif

		if (GetOperandDataType(psContext, &psInst->asOperands[0]) == SVT_UINT)
		{
			ui32Flags = TO_FLAG_UNSIGNED_INTEGER;
		}

		CallTernaryOp(psContext, "*", "+", psInst, 0, 1, 2, 3, ui32Flags);
		break;
	}
	case OPCODE_DADD:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//DADD\n");
#endif
		CallBinaryOp(psContext, "+", psInst, 0, 1, 2, SVT_DOUBLE);
		break;
	}
	case OPCODE_IADD:
	{
		SHADER_VARIABLE_TYPE eType = SVT_INT;
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//IADD\n");
#endif
		//Is this a signed or unsigned add?
		if (GetOperandDataType(psContext, &psInst->asOperands[0]) == SVT_UINT)
		{
			eType = SVT_UINT;
		}
		CallBinaryOp(psContext, "+", psInst, 0, 1, 2, eType);
		break;
	}
	case OPCODE_ADD:
	{

#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//ADD\n");
#endif
		CallBinaryOp(psContext, "+", psInst, 0, 1, 2, SVT_FLOAT);
		break;
	}
	case OPCODE_OR:
	{
		/*Todo: vector version */
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//OR\n");
#endif
		CallBinaryOp(psContext, "|", psInst, 0, 1, 2, SVT_UINT);
		break;
	}
	case OPCODE_AND:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//AND\n");
#endif
		CallBinaryOp(psContext, "&", psInst, 0, 1, 2, SVT_UINT);
		break;
	}
	case OPCODE_GE:
	{
		/*
			dest = vec4(greaterThanEqual(vec4(srcA), vec4(srcB));
			Caveat: The result is a boolean but HLSL asm returns 0xFFFFFFFF/0x0 instead.
			*/
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//GE\n");
#endif
		AddComparision(psContext, psInst, CMP_GE, TO_FLAG_NONE, NULL);
		break;
	}
	case OPCODE_MUL:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//MUL\n");
#endif
		CallBinaryOp(psContext, "*", psInst, 0, 1, 2, SVT_FLOAT);
		break;
	}
	case OPCODE_IMUL:
	{
		SHADER_VARIABLE_TYPE eType = SVT_INT;
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//IMUL\n");
#endif
		if (GetOperandDataType(psContext, &psInst->asOperands[1]) == SVT_UINT)
		{
			eType = SVT_UINT;
		}

		ASSERT(psInst->asOperands[0].eType == OPERAND_TYPE_NULL);

		CallBinaryOp(psContext, "*", psInst, 1, 2, 3, eType);
		break;
	}
	case OPCODE_UDIV:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//UDIV\n");
#endif
		//destQuotient, destRemainder, src0, src1
		CallBinaryOp(psContext, "/", psInst, 0, 2, 3, SVT_UINT);
		CallBinaryOp(psContext, "%", psInst, 1, 2, 3, SVT_UINT);
		break;
	}
	case OPCODE_DIV:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//DIV\n");
#endif
		CallBinaryOp(psContext, "/", psInst, 0, 1, 2, SVT_FLOAT);
		break;
	}
	case OPCODE_SINCOS:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//SINCOS\n");
#endif
		// Need careful ordering if src == dest[0], as then the cos() will be reading from wrong value
		if (psInst->asOperands[0].eType == psInst->asOperands[2].eType &&
			psInst->asOperands[0].ui32RegisterNumber == psInst->asOperands[2].ui32RegisterNumber)
		{
			// sin() result overwrites source, do cos() first.
			// The case where both write the src shouldn't really happen anyway.
			if (psInst->asOperands[1].eType != OPERAND_TYPE_NULL)
			{
				CallHelper1(psContext, "cos", psInst, 1, 2, 1);
			}

			if (psInst->asOperands[0].eType != OPERAND_TYPE_NULL)
			{
				CallHelper1(psContext, "sin", psInst, 0, 2, 1);
			}
		}
		else
		{
			if (psInst->asOperands[0].eType != OPERAND_TYPE_NULL)
			{
				CallHelper1(psContext, "sin", psInst, 0, 2, 1);
			}

			if (psInst->asOperands[1].eType != OPERAND_TYPE_NULL)
			{
				CallHelper1(psContext, "cos", psInst, 1, 2, 1);
			}
		}
		break;
	}

	case OPCODE_DP2:
	{
		SHADER_VARIABLE_TYPE eDestDataType = GetOperandDataType(psContext, &psInst->asOperands[0]);
		int numParenthesis = 0;
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//DP2\n");
#endif
		AddIndentation(psContext);
		AddAssignToDest(psContext, &psInst->asOperands[0], SVT_FLOAT, 1, &numParenthesis);
		bcatcstr(glsl, "dot(");
		TranslateOperandWithMask(psContext, &psInst->asOperands[1], TO_AUTO_BITCAST_TO_FLOAT, 3 /* .xy */);
		bcatcstr(glsl, ", ");
		TranslateOperandWithMask(psContext, &psInst->asOperands[2], TO_AUTO_BITCAST_TO_FLOAT, 3 /* .xy */);
		bcatcstr(glsl, ")");
		AddAssignPrologue(psContext, numParenthesis);
		break;
	}
	case OPCODE_DP3:
	{
		int numParenthesis = 0;
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//DP3\n");
#endif
		AddIndentation(psContext);
		AddAssignToDest(psContext, &psInst->asOperands[0], SVT_FLOAT, 1, &numParenthesis);
		bcatcstr(glsl, "dot(");
		TranslateOperandWithMask(psContext, &psInst->asOperands[1], TO_AUTO_BITCAST_TO_FLOAT, 7 /* .xyz */);
		bcatcstr(glsl, ", ");
		TranslateOperandWithMask(psContext, &psInst->asOperands[2], TO_AUTO_BITCAST_TO_FLOAT, 7 /* .xyz */);
		bcatcstr(glsl, ")");
		AddAssignPrologue(psContext, numParenthesis);
		break;
	}
	case OPCODE_DP4:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//DP4\n");
#endif
		CallHelper2(psContext, "dot", psInst, 0, 1, 2, 0);
		break;
	}
	case OPCODE_INE:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//INE\n");
#endif
		AddComparision(psContext, psInst, CMP_NE, TO_FLAG_INTEGER, NULL);
		break;
	}
	case OPCODE_NE:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//NE\n");
#endif
		AddComparision(psContext, psInst, CMP_NE, TO_FLAG_NONE, NULL);
		break;
	}
	case OPCODE_IGE:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//IGE\n");
#endif
		AddComparision(psContext, psInst, CMP_GE, TO_FLAG_INTEGER, psNextInst);
		break;
	}
	case OPCODE_ILT:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//ILT\n");
#endif
		AddComparision(psContext, psInst, CMP_LT, TO_FLAG_INTEGER, NULL);
		break;
	}
	case OPCODE_LT:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//LT\n");
#endif
		AddComparision(psContext, psInst, CMP_LT, TO_FLAG_NONE, NULL);
		break;
	}
	case OPCODE_IEQ:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//IEQ\n");
#endif
		AddComparision(psContext, psInst, CMP_EQ, TO_FLAG_INTEGER, NULL);
		break;
	}
	case OPCODE_ULT:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//ULT\n");
#endif
		AddComparision(psContext, psInst, CMP_LT, TO_FLAG_UNSIGNED_INTEGER, NULL);
		break;
	}
	case OPCODE_UGE:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//UGE\n");
#endif
		AddComparision(psContext, psInst, CMP_GE, TO_FLAG_UNSIGNED_INTEGER, NULL);
		break;
	}
	case OPCODE_MOVC:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//MOVC\n");
#endif
		AddMOVCBinaryOp(psContext, &psInst->asOperands[0], &psInst->asOperands[1], &psInst->asOperands[2], &psInst->asOperands[3]);
		break;
	}
	case OPCODE_SWAPC:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//SWAPC\n");
#endif
		// TODO needs temps!!
		AddMOVCBinaryOp(psContext, &psInst->asOperands[0], &psInst->asOperands[2], &psInst->asOperands[4], &psInst->asOperands[3]);
		AddMOVCBinaryOp(psContext, &psInst->asOperands[1], &psInst->asOperands[2], &psInst->asOperands[3], &psInst->asOperands[4]);
		break;
	}

	case OPCODE_LOG:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//LOG\n");
#endif
		CallHelper1(psContext, "log2", psInst, 0, 1, 1);
		break;
	}
	case OPCODE_RSQ:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//RSQ\n");
#endif
		CallHelper1(psContext, "inversesqrt", psInst, 0, 1, 1);
		break;
	}
	case OPCODE_EXP:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//EXP\n");
#endif
		CallHelper1(psContext, "exp2", psInst, 0, 1, 1);
		break;
	}
	case OPCODE_SQRT:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//SQRT\n");
#endif
		CallHelper1(psContext, "sqrt", psInst, 0, 1, 1);
		break;
	}
	case OPCODE_ROUND_PI:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//ROUND_PI\n");
#endif
		CallHelper1(psContext, "ceil", psInst, 0, 1, 1);
		break;
	}
	case OPCODE_ROUND_NI:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//ROUND_NI\n");
#endif
		CallHelper1(psContext, "floor", psInst, 0, 1, 1);
		break;
	}
	case OPCODE_ROUND_Z:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//ROUND_Z\n");
#endif
		CallHelper1(psContext, "trunc", psInst, 0, 1, 1);
		break;
	}
	case OPCODE_ROUND_NE:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//ROUND_NE\n");
#endif
		CallHelper1(psContext, "roundEven", psInst, 0, 1, 1);
		break;
	}
	case OPCODE_FRC:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//FRC\n");
#endif
		CallHelper1(psContext, "fract", psInst, 0, 1, 1);
		break;
	}
	case OPCODE_IMAX:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//IMAX\n");
#endif
		CallHelper2Int(psContext, "max", psInst, 0, 1, 2, 1);
		break;
	}
	case OPCODE_MAX:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//MAX\n");
#endif
		CallHelper2(psContext, "max", psInst, 0, 1, 2, 1);
		break;
	}
	case OPCODE_IMIN:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//IMIN\n");
#endif
		CallHelper2Int(psContext, "min", psInst, 0, 1, 2, 1);
		break;
	}
	case OPCODE_MIN:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//MIN\n");
#endif
		CallHelper2(psContext, "min", psInst, 0, 1, 2, 1);
		break;
	}
	case OPCODE_GATHER4:
	{
		//dest, coords, tex, sampler
		const RESOURCE_DIMENSION eResDim = psContext->psShader->aeResourceDims[psInst->asOperands[2].ui32RegisterNumber];
		const int useCombinedTextureSamplers = (psContext->flags & HLSLCC_FLAG_COMBINE_TEXTURE_SAMPLERS) ? 1 : 0;
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//GATHER4\n");
#endif
		//gather4 r7.xyzw, r3.xyxx, t3.xyzw, s0.x
		AddIndentation(psContext); // TODO FIXME integer samplers
		AddAssignToDest(psContext, &psInst->asOperands[0], SVT_FLOAT, GetNumSwizzleElements(&psInst->asOperands[2]), &numParenthesis);
		bcatcstr(glsl, "textureGather(");

		if (!useCombinedTextureSamplers)
			ResourceName(glsl, psContext, RGROUP_TEXTURE, psInst->asOperands[2].ui32RegisterNumber, 0);
		else
			bconcat(glsl, TextureSamplerName(&psContext->psShader->sInfo, psInst->asOperands[2].ui32RegisterNumber, psInst->asOperands[3].ui32RegisterNumber, 0));

		bcatcstr(glsl, ", ");
		TranslateTexCoord(psContext, eResDim, &psInst->asOperands[1]);
		bcatcstr(glsl, ")");
		// iWriteMaskEnabled is forced off during DecodeOperand because swizzle on sampler uniforms
		// does not make sense. But need to re-enable to correctly swizzle this particular instruction.
		psInst->asOperands[2].iWriteMaskEnabled = 1;
		TranslateOperandSwizzle(psContext, &psInst->asOperands[2]);

		AddSwizzleUsingElementCount(psContext, GetNumSwizzleElements(&psInst->asOperands[0]));
		AddAssignPrologue(psContext, numParenthesis);
		break;
	}
	case OPCODE_GATHER4_PO_C:
	{
		//dest, coords, offset, tex, sampler, srcReferenceValue
		const RESOURCE_DIMENSION eResDim = psContext->psShader->aeResourceDims[psInst->asOperands[3].ui32RegisterNumber];
		const int useCombinedTextureSamplers = (psContext->flags & HLSLCC_FLAG_COMBINE_TEXTURE_SAMPLERS) ? 1 : 0;
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//GATHER4_PO_C\n");
#endif

		AddIndentation(psContext); // TODO FIXME integer samplers
		AddAssignToDest(psContext, &psInst->asOperands[0], SVT_FLOAT, GetNumSwizzleElements(&psInst->asOperands[2]), &numParenthesis);
		bcatcstr(glsl, "textureGatherOffset(");

		if (!useCombinedTextureSamplers)
			ResourceName(glsl, psContext, RGROUP_TEXTURE, psInst->asOperands[3].ui32RegisterNumber, 1);
		else
			bconcat(glsl, TextureSamplerName(&psContext->psShader->sInfo, psInst->asOperands[3].ui32RegisterNumber, psInst->asOperands[3].ui32RegisterNumber, 1));

		bcatcstr(glsl, ", ");

		TranslateTexCoord(psContext, eResDim, &psInst->asOperands[1]);

		bcatcstr(glsl, ", ");
		TranslateOperand(psContext, &psInst->asOperands[5], TO_FLAG_NONE);

		bcatcstr(glsl, ", ivec2(");
		//ivec2 offset
		psInst->asOperands[2].aui32Swizzle[2] = 0xFFFFFFFF;
		psInst->asOperands[2].aui32Swizzle[3] = 0xFFFFFFFF;
		TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NONE);
		bcatcstr(glsl, "))");
		// iWriteMaskEnabled is forced off during DecodeOperand because swizzle on sampler uniforms
		// does not make sense. But need to re-enable to correctly swizzle this particular instruction.
		psInst->asOperands[2].iWriteMaskEnabled = 1;
		TranslateOperandSwizzle(psContext, &psInst->asOperands[3]);
		AddSwizzleUsingElementCount(psContext, GetNumSwizzleElements(&psInst->asOperands[0]));
		AddAssignPrologue(psContext, numParenthesis);
		break;
	}
	case OPCODE_GATHER4_PO:
	{
		//dest, coords, offset, tex, sampler
		const int useCombinedTextureSamplers = (psContext->flags & HLSLCC_FLAG_COMBINE_TEXTURE_SAMPLERS) ? 1 : 0;
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//GATHER4_PO\n");
#endif

		AddIndentation(psContext); // TODO FIXME integer samplers
		AddAssignToDest(psContext, &psInst->asOperands[0], SVT_FLOAT, GetNumSwizzleElements(&psInst->asOperands[2]), &numParenthesis);
		bcatcstr(glsl, "textureGatherOffset(");

		if (!useCombinedTextureSamplers)
			ResourceName(glsl, psContext, RGROUP_TEXTURE, psInst->asOperands[3].ui32RegisterNumber, 0);
		else
			bconcat(glsl, TextureSamplerName(&psContext->psShader->sInfo, psInst->asOperands[3].ui32RegisterNumber, psInst->asOperands[4].ui32RegisterNumber, 0));

		bcatcstr(glsl, ", ");
		//Texture coord cannot be vec4
		//Determining if it is a vec3 for vec2 yet to be done.
		psInst->asOperands[1].aui32Swizzle[2] = 0xFFFFFFFF;
		psInst->asOperands[1].aui32Swizzle[3] = 0xFFFFFFFF;
		TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_NONE);

		bcatcstr(glsl, ", ivec2(");
		//ivec2 offset
		psInst->asOperands[2].aui32Swizzle[2] = 0xFFFFFFFF;
		psInst->asOperands[2].aui32Swizzle[3] = 0xFFFFFFFF;
		TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NONE);
		bcatcstr(glsl, "))");
		// iWriteMaskEnabled is forced off during DecodeOperand because swizzle on sampler uniforms
		// does not make sense. But need to re-enable to correctly swizzle this particular instruction.
		psInst->asOperands[2].iWriteMaskEnabled = 1;
		TranslateOperandSwizzle(psContext, &psInst->asOperands[3]);
		AddSwizzleUsingElementCount(psContext, GetNumSwizzleElements(&psInst->asOperands[0]));
		AddAssignPrologue(psContext, numParenthesis);
		break;
	}
	case OPCODE_GATHER4_C:
	{
		//dest, coords, tex, sampler srcReferenceValue
		const int useCombinedTextureSamplers = (psContext->flags & HLSLCC_FLAG_COMBINE_TEXTURE_SAMPLERS) ? 1 : 0;
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//GATHER4_C\n");
#endif

		AddIndentation(psContext); // TODO FIXME integer samplers
		AddAssignToDest(psContext, &psInst->asOperands[0], SVT_FLOAT, GetNumSwizzleElements(&psInst->asOperands[2]), &numParenthesis);
		bcatcstr(glsl, "textureGather(");

		if (!useCombinedTextureSamplers)
			ResourceName(glsl, psContext, RGROUP_TEXTURE, psInst->asOperands[2].ui32RegisterNumber, 1);
		else
			bconcat(glsl, TextureSamplerName(&psContext->psShader->sInfo, psInst->asOperands[2].ui32RegisterNumber, psInst->asOperands[3].ui32RegisterNumber, 1));

		bcatcstr(glsl, ", ");
		//Texture coord cannot be vec4
		//Determining if it is a vec3 for vec2 yet to be done.
		psInst->asOperands[1].aui32Swizzle[2] = 0xFFFFFFFF;
		psInst->asOperands[1].aui32Swizzle[3] = 0xFFFFFFFF;
		TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_NONE);

		bcatcstr(glsl, ", ");
		TranslateOperand(psContext, &psInst->asOperands[4], TO_FLAG_NONE);
		bcatcstr(glsl, ")");
		// iWriteMaskEnabled is forced off during DecodeOperand because swizzle on sampler uniforms
		// does not make sense. But need to re-enable to correctly swizzle this particular instruction.
		psInst->asOperands[2].iWriteMaskEnabled = 1;
		TranslateOperandSwizzle(psContext, &psInst->asOperands[2]);
		AddSwizzleUsingElementCount(psContext, GetNumSwizzleElements(&psInst->asOperands[0]));
		AddAssignPrologue(psContext, numParenthesis);
		break;
	}
	case OPCODE_SAMPLE:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//SAMPLE\n");
#endif
		TranslateTextureSample(psContext, psInst, TEXSMP_FLAG_NONE);
		break;
	}
	case OPCODE_SAMPLE_L:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//SAMPLE_L\n");
#endif
		TranslateTextureSample(psContext, psInst, TEXSMP_FLAG_LOD);
		break;
	}
	case OPCODE_SAMPLE_C:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//SAMPLE_C\n");
#endif

		TranslateTextureSample(psContext, psInst, TEXSMP_FLAG_DEPTHCOMPARE);
		break;
	}
	case OPCODE_SAMPLE_C_LZ:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//SAMPLE_C_LZ\n");
#endif

		TranslateTextureSample(psContext, psInst, TEXSMP_FLAG_DEPTHCOMPARE | TEXSMP_FLAG_FIRSTLOD);
		break;
	}
	case OPCODE_SAMPLE_D:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//SAMPLE_D\n");
#endif

		TranslateTextureSample(psContext, psInst, TEXSMP_FLAGS_GRAD);
		break;
	}
	case OPCODE_SAMPLE_B:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//SAMPLE_B\n");
#endif

		TranslateTextureSample(psContext, psInst, TEXSMP_FLAG_BIAS);
		break;
	}
	case OPCODE_RET:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//RET\n");
#endif
		if (psContext->havePostShaderCode[psContext->currentPhase])
		{
#ifdef _DEBUG
			AddIndentation(psContext);
			bcatcstr(glsl, "//--- Post shader code ---\n");
#endif
			bconcat(glsl, psContext->postShaderCode[psContext->currentPhase]);
#ifdef _DEBUG
			AddIndentation(psContext);
			bcatcstr(glsl, "//--- End post shader code ---\n");
#endif
		}
		AddIndentation(psContext);
		bcatcstr(glsl, "return;\n");
		break;
	}
	case OPCODE_INTERFACE_CALL:
	{
		const char* name;
		ShaderVar* psVar;
		uint32_t varFound;

		uint32_t funcPointer;
		uint32_t funcTableIndex;
		uint32_t funcTable;
		uint32_t funcBodyIndex;
		uint32_t funcBody;
		uint32_t ui32NumBodiesPerTable;

#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//INTERFACE_CALL\n");
#endif

		ASSERT(psInst->asOperands[0].eIndexRep[0] == OPERAND_INDEX_IMMEDIATE32);

		funcPointer = psInst->asOperands[0].aui32ArraySizes[0];
		funcTableIndex = psInst->asOperands[0].aui32ArraySizes[1];
		funcBodyIndex = psInst->ui32FuncIndexWithinInterface;

		ui32NumBodiesPerTable = psContext->psShader->funcPointer[funcPointer].ui32NumBodiesPerTable;

		funcTable = psContext->psShader->funcPointer[funcPointer].aui32FuncTables[funcTableIndex];

		funcBody = psContext->psShader->funcTable[funcTable].aui32FuncBodies[funcBodyIndex];

		varFound = GetInterfaceVarFromOffset(funcPointer, &psContext->psShader->sInfo, &psVar);

		ASSERT(varFound);

		name = &psVar->Name[0];

		AddIndentation(psContext);
		bcatcstr(glsl, name);
		TranslateOperandIndexMAD(psContext, &psInst->asOperands[0], 1, ui32NumBodiesPerTable, funcBodyIndex);
		//bformata(glsl, "[%d]", funcBodyIndex);
		bcatcstr(glsl, "();\n");
		break;
	}
	case OPCODE_LABEL:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//LABEL\n");
#endif
		--psContext->indent;
		AddIndentation(psContext);
		bcatcstr(glsl, "}\n"); //Closing brace ends the previous function.
		AddIndentation(psContext);

		bcatcstr(glsl, "subroutine(SubroutineType)\n");
		bcatcstr(glsl, "void ");
		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_DESTINATION);
		bcatcstr(glsl, "(){\n");
		++psContext->indent;
		break;
	}
	case OPCODE_COUNTBITS:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//COUNTBITS\n");
#endif
		AddIndentation(psContext);
		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_INTEGER | TO_FLAG_DESTINATION);
		bcatcstr(glsl, " = bitCount(");
		TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_INTEGER);
		bcatcstr(glsl, ");\n");
		break;
	}
	case OPCODE_FIRSTBIT_HI:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//FIRSTBIT_HI\n");
#endif
		AddIndentation(psContext);
		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_UNSIGNED_INTEGER | TO_FLAG_DESTINATION);
		bcatcstr(glsl, " = findMSB(");
		TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_UNSIGNED_INTEGER);
		bcatcstr(glsl, ");\n");
		break;
	}
	case OPCODE_FIRSTBIT_LO:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//FIRSTBIT_LO\n");
#endif
		AddIndentation(psContext);
		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_UNSIGNED_INTEGER | TO_FLAG_DESTINATION);
		bcatcstr(glsl, " = findLSB(");
		TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_UNSIGNED_INTEGER);
		bcatcstr(glsl, ");\n");
		break;
	}
	case OPCODE_FIRSTBIT_SHI: //signed high
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//FIRSTBIT_SHI\n");
#endif
		AddIndentation(psContext);
		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_INTEGER | TO_FLAG_DESTINATION);
		bcatcstr(glsl, " = findMSB(");
		TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_INTEGER);
		bcatcstr(glsl, ");\n");
		break;
	}
	case OPCODE_BFREV:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//BFREV\n");
#endif
		AddIndentation(psContext);
		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_INTEGER | TO_FLAG_DESTINATION);
		bcatcstr(glsl, " = bitfieldReverse(");
		TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_INTEGER);
		bcatcstr(glsl, ");\n");
		break;
	}
	case OPCODE_BFI:
	{
		uint32_t numelements_width = GetNumSwizzleElements(&psInst->asOperands[1]);
		uint32_t numelements_offset = GetNumSwizzleElements(&psInst->asOperands[2]);
		uint32_t numelements_dest = GetNumSwizzleElements(&psInst->asOperands[0]);
		uint32_t numoverall_elements = min(min(numelements_width, numelements_offset), numelements_dest);
		uint32_t i, j;
		static const char* bfi_elementidx[] = { "x", "y", "z", "w" };
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//BFI\n");
#endif

		AddIndentation(psContext);
		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_INTEGER | TO_FLAG_DESTINATION);
		bformata(glsl, " = ivec%d(", numoverall_elements);
		for (i = 0; i < numoverall_elements; ++i)
		{
			bcatcstr(glsl, "bitfieldInsert(");

			for (j = 4; j >= 1; --j)
			{
				uint32_t opSwizzleCount = GetNumSwizzleElements(&psInst->asOperands[j]);

				if (opSwizzleCount != 1)
					bcatcstr(glsl, " (");
				TranslateOperand(psContext, &psInst->asOperands[j], TO_FLAG_INTEGER);
				if (opSwizzleCount != 1)
					bformata(glsl, " ).%s", bfi_elementidx[i]);
				if (j != 1)
					bcatcstr(glsl, ",");
			}

			bcatcstr(glsl, ") ");
			if (i + 1 != numoverall_elements)
				bcatcstr(glsl, ", ");
		}

		bcatcstr(glsl, ").");
		for (i = 0; i < numoverall_elements; ++i)
			bformata(glsl, "%s", bfi_elementidx[i]);
		bcatcstr(glsl, ";\n");
		break;
	}
	case OPCODE_CUT:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//CUT\n");
#endif
		AddIndentation(psContext);
		bcatcstr(glsl, "EndPrimitive();\n");
		break;
	}
	case OPCODE_EMIT:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//EMIT\n");
#endif
		if (psContext->havePostShaderCode[psContext->currentPhase])
		{
#ifdef _DEBUG
			AddIndentation(psContext);
			bcatcstr(glsl, "//--- Post shader code ---\n");
#endif
			bconcat(glsl, psContext->postShaderCode[psContext->currentPhase]);
#ifdef _DEBUG
			AddIndentation(psContext);
			bcatcstr(glsl, "//--- End post shader code ---\n");
#endif
		}

		AddIndentation(psContext);
		bcatcstr(glsl, "EmitVertex();\n");
		break;
	}
	case OPCODE_EMITTHENCUT:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//EMITTHENCUT\n");
#endif
		AddIndentation(psContext);
		bcatcstr(glsl, "EmitVertex();\nEndPrimitive();\n");
		break;
	}

	case OPCODE_CUT_STREAM:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//CUT\n");
#endif
		AddIndentation(psContext);
		bcatcstr(glsl, "EndStreamPrimitive(");
		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_DESTINATION);
		bcatcstr(glsl, ");\n");

		break;
	}
	case OPCODE_EMIT_STREAM:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//EMIT_STREAM\n");
#endif
		if (psContext->havePostShaderCode[psContext->currentPhase])
		{
#ifdef _DEBUG
			AddIndentation(psContext);
			bcatcstr(glsl, "//--- Post shader code ---\n");
#endif
			bconcat(glsl, psContext->postShaderCode[psContext->currentPhase]);
#ifdef _DEBUG
			AddIndentation(psContext);
			bcatcstr(glsl, "//--- End post shader code ---\n");
#endif
		}

		AddIndentation(psContext);
		bcatcstr(glsl, "EmitStreamVertex(");
		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_DESTINATION);
		bcatcstr(glsl, ");\n");
		break;
	}
	case OPCODE_EMITTHENCUT_STREAM:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//EMITTHENCUT\n");
#endif
		AddIndentation(psContext);
		bcatcstr(glsl, "EmitStreamVertex(");
		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_DESTINATION);
		bcatcstr(glsl, ");\n");
		bcatcstr(glsl, "EndStreamPrimitive(");
		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_DESTINATION);
		bcatcstr(glsl, ");\n");
		break;
	}
	case OPCODE_REP:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//REP\n");
#endif
		//Need to handle nesting.
		//Max of 4 for rep - 'Flow Control Limitations' http://msdn.microsoft.com/en-us/library/windows/desktop/bb219848(v=vs.85).aspx

		AddIndentation(psContext);
		bcatcstr(glsl, "RepCounter = ");
		TranslateOperandWithMask(psContext, &psInst->asOperands[0], TO_FLAG_INTEGER, OPERAND_4_COMPONENT_MASK_X);
		bcatcstr(glsl, ";\n");

		AddIndentation(psContext);
		bcatcstr(glsl, "while(RepCounter!=0){\n");
		++psContext->indent;
		break;
	}
	case OPCODE_ENDREP:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//ENDREP\n");
#endif
		AddIndentation(psContext);
		bcatcstr(glsl, "RepCounter--;\n");

		--psContext->indent;

		AddIndentation(psContext);
		bcatcstr(glsl, "}\n");
		break;
	}
	case OPCODE_LOOP:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//LOOP\n");
#endif
		AddIndentation(psContext);

		if (psInst->ui32NumOperands == 2)
		{
			//DX9 version
			ASSERT(psInst->asOperands[0].eType == OPERAND_TYPE_SPECIAL_LOOPCOUNTER);
			bcatcstr(glsl, "for(");
			bcatcstr(glsl, "LoopCounter = ");
			TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_NONE);
			bcatcstr(glsl, ".y, ZeroBasedCounter = 0;");
			bcatcstr(glsl, "ZeroBasedCounter < ");
			TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_NONE);
			bcatcstr(glsl, ".x;");

			bcatcstr(glsl, "LoopCounter += ");
			TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_NONE);
			bcatcstr(glsl, ".z, ZeroBasedCounter++){\n");
			++psContext->indent;
		}
		else
		{
			bcatcstr(glsl, "while(true){\n");
			++psContext->indent;
		}
		break;
	}
	case OPCODE_ENDLOOP:
	{
		--psContext->indent;
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//ENDLOOP\n");
#endif
		AddIndentation(psContext);
		bcatcstr(glsl, "}\n");
		break;
	}
	case OPCODE_BREAK:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//BREAK\n");
#endif
		AddIndentation(psContext);
		bcatcstr(glsl, "break;\n");
		break;
	}
	case OPCODE_BREAKC:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//BREAKC\n");
#endif
		AddIndentation(psContext);

		TranslateConditional(psContext, psInst, glsl);
		break;
	}
	case OPCODE_CONTINUEC:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//CONTINUEC\n");
#endif
		AddIndentation(psContext);

		TranslateConditional(psContext, psInst, glsl);
		break;
	}
	case OPCODE_IF:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//IF\n");
#endif
		AddIndentation(psContext);

		TranslateConditional(psContext, psInst, glsl);
		++psContext->indent;
		break;
	}
	case OPCODE_RETC:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//RETC\n");
#endif
		AddIndentation(psContext);

		TranslateConditional(psContext, psInst, glsl);
		break;
	}
	case OPCODE_ELSE:
	{
		--psContext->indent;
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//ELSE\n");
#endif
		AddIndentation(psContext);
		bcatcstr(glsl, "} else {\n");
		psContext->indent++;
		break;
	}
	case OPCODE_ENDSWITCH:
	case OPCODE_ENDIF:
	{
		--psContext->indent;
		AddIndentation(psContext);
		bcatcstr(glsl, "//ENDIF\n");
		AddIndentation(psContext);
		bcatcstr(glsl, "}\n");
		break;
	}
	case OPCODE_CONTINUE:
	{
		AddIndentation(psContext);
		bcatcstr(glsl, "continue;\n");
		break;
	}
	case OPCODE_DEFAULT:
	{
		--psContext->indent;
		AddIndentation(psContext);
		bcatcstr(glsl, "default:\n");
		++psContext->indent;
		break;
	}
	case OPCODE_NOP:
	{
		break;
	}
	case OPCODE_SYNC:
	{
		const uint32_t ui32SyncFlags = psInst->ui32SyncFlags;

#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//SYNC\n");
#endif

		if (ui32SyncFlags & SYNC_THREADS_IN_GROUP)
		{
			AddIndentation(psContext);
			bcatcstr(glsl, "groupMemoryBarrier();\n");
		}
		if (ui32SyncFlags & SYNC_THREAD_GROUP_SHARED_MEMORY)
		{
			AddIndentation(psContext);
			bcatcstr(glsl, "memoryBarrierShared();\n");
		}
		if (ui32SyncFlags & (SYNC_UNORDERED_ACCESS_VIEW_MEMORY_GROUP | SYNC_UNORDERED_ACCESS_VIEW_MEMORY_GLOBAL))
		{
			AddIndentation(psContext);
			bcatcstr(glsl, "memoryBarrier();\n");
		}
		break;
	}
	case OPCODE_SWITCH:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//SWITCH\n");
#endif
		AddIndentation(psContext);
		bcatcstr(glsl, "switch(int(");
		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_INTEGER);
		bcatcstr(glsl, ")){\n");

		psContext->indent += 2;
		break;
	}
	case OPCODE_CASE:
	{
		--psContext->indent;
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//case\n");
#endif
		AddIndentation(psContext);

		bcatcstr(glsl, "case ");
		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_INTEGER);
		bcatcstr(glsl, ":\n");

		++psContext->indent;
		break;
	}
	case OPCODE_EQ:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//EQ\n");
#endif
		AddComparision(psContext, psInst, CMP_EQ, TO_FLAG_NONE, NULL);
		break;
	}
	case OPCODE_USHR:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//USHR\n");
#endif
		CallBinaryOp(psContext, ">>", psInst, 0, 1, 2, SVT_UINT);
		break;
	}
	case OPCODE_ISHL:
	{
		SHADER_VARIABLE_TYPE eType = SVT_INT;

#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//ISHL\n");
#endif

		if (GetOperandDataType(psContext, &psInst->asOperands[0]) == SVT_UINT)
		{
			eType = SVT_UINT;
		}

		CallBinaryOp(psContext, "<<", psInst, 0, 1, 2, eType);
		break;
	}
	case OPCODE_ISHR:
	{
		SHADER_VARIABLE_TYPE eType = SVT_INT;
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//ISHR\n");
#endif

		if (GetOperandDataType(psContext, &psInst->asOperands[0]) == SVT_UINT)
		{
			eType = SVT_UINT;
		}

		CallBinaryOp(psContext, ">>", psInst, 0, 1, 2, eType);
		break;
	}
	case OPCODE_LD:
	case OPCODE_LD_MS:
	{
		ResourceBinding* psBinding = 0;
		uint32_t dstSwizCount = GetNumSwizzleElements(&psInst->asOperands[0]);
#ifdef _DEBUG
		AddIndentation(psContext);
		if (psInst->eOpcode == OPCODE_LD)
			bcatcstr(glsl, "//LD\n");
		else
			bcatcstr(glsl, "//LD_MS\n");
#endif

		GetResourceFromBindingPoint(RGROUP_TEXTURE, psInst->asOperands[2].ui32RegisterNumber, &psContext->psShader->sInfo, &psBinding);

		if (psInst->bAddressOffset)
		{
			TranslateTexelFetchOffset(psContext, psInst, psBinding, glsl);
		}
		else
		{
			TranslateTexelFetch(psContext, psInst, psBinding, glsl);
		}
		break;
	}
	case OPCODE_DISCARD:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//DISCARD\n");
#endif
		AddIndentation(psContext);
		if (psContext->psShader->ui32MajorVersion <= 3)
		{
			bcatcstr(glsl, "if(any(lessThan((");
			TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_NONE);

			if (psContext->psShader->ui32MajorVersion == 1)
			{
				/* SM1.X only kills based on the rgb channels */
				bcatcstr(glsl, ").xyz, vec3(0)))){discard;}\n");
			}
			else
			{
				bcatcstr(glsl, "), vec4(0)))){discard;}\n");
			}
		}
		else if (psInst->eBooleanTestType == INSTRUCTION_TEST_ZERO)
		{
			bcatcstr(glsl, "if((");
			TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_INTEGER);
			bcatcstr(glsl, ")==0){discard;}\n");
		}
		else
		{
			ASSERT(psInst->eBooleanTestType == INSTRUCTION_TEST_NONZERO);
			bcatcstr(glsl, "if((");
			TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_INTEGER);
			bcatcstr(glsl, ")!=0){discard;}\n");
		}
		break;
	}
	case OPCODE_LOD:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//LOD\n");
#endif
		//LOD computes the following vector (ClampedLOD, NonClampedLOD, 0, 0)

		AddIndentation(psContext);
		AddAssignToDest(psContext, &psInst->asOperands[0], SVT_FLOAT, 4, &numParenthesis);

		//If the core language does not have query-lod feature,
		//then the extension is used. The name of the function
		//changed between extension and core.
		if (HaveQueryLod(psContext->psShader->eTargetLanguage))
		{
			bcatcstr(glsl, "textureQueryLod(");
		}
		else
		{
			bcatcstr(glsl, "textureQueryLOD(");
		}

		TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NONE);
		bcatcstr(glsl, ",");
		TranslateTexCoord(psContext,
			psContext->psShader->aeResourceDims[psInst->asOperands[2].ui32RegisterNumber],
			&psInst->asOperands[1]);
		bcatcstr(glsl, ")");

		//The swizzle on srcResource allows the returned values to be swizzled arbitrarily before they are written to the destination.

		// iWriteMaskEnabled is forced off during DecodeOperand because swizzle on sampler uniforms
		// does not make sense. But need to re-enable to correctly swizzle this particular instruction.
		psInst->asOperands[2].iWriteMaskEnabled = 1;
		TranslateOperandSwizzleWithMask(psContext, &psInst->asOperands[2], GetOperandWriteMask(&psInst->asOperands[0]));
		AddAssignPrologue(psContext, numParenthesis);
		break;
	}
	case OPCODE_EVAL_CENTROID:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//EVAL_CENTROID\n");
#endif
		AddIndentation(psContext);
		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_DESTINATION);
		bcatcstr(glsl, " = interpolateAtCentroid(");
		//interpolateAtCentroid accepts in-qualified variables.
		//As long as bytecode only writes vX registers in declarations
		//we should be able to use the declared name directly.
		TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_DECLARATION_NAME);
		bcatcstr(glsl, ");\n");
		break;
	}
	case OPCODE_EVAL_SAMPLE_INDEX:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//EVAL_SAMPLE_INDEX\n");
#endif
		AddIndentation(psContext);
		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_DESTINATION);
		bcatcstr(glsl, " = interpolateAtSample(");
		//interpolateAtSample accepts in-qualified variables.
		//As long as bytecode only writes vX registers in declarations
		//we should be able to use the declared name directly.
		TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_DECLARATION_NAME);
		bcatcstr(glsl, ", ");
		TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_INTEGER);
		bcatcstr(glsl, ");\n");
		break;
	}
	case OPCODE_EVAL_SNAPPED:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//EVAL_SNAPPED\n");
#endif
		AddIndentation(psContext);
		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_DESTINATION);
		bcatcstr(glsl, " = interpolateAtOffset(");
		//interpolateAtOffset accepts in-qualified variables.
		//As long as bytecode only writes vX registers in declarations
		//we should be able to use the declared name directly.
		TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_DECLARATION_NAME);
		bcatcstr(glsl, ", ");
		TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_INTEGER);
		bcatcstr(glsl, ".xy);\n");
		break;
	}
	case OPCODE_LD_STRUCTURED:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//LD_STRUCTURED\n");
#endif
		TranslateShaderStorageLoad(psContext, psInst);
		break;
	}
	case OPCODE_LD_UAV_TYPED:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//LD_UAV_TYPED\n");
#endif
		switch (psInst->eResDim)
		{
		case RESOURCE_DIMENSION_TEXTURE1D:
			AddIndentation(psContext);
			TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_DESTINATION);
			bcatcstr(glsl, " = imageLoad(");
			TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NAME_ONLY);
			bcatcstr(glsl, ", (");
			TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_INTEGER);
			bformata(glsl, ").x)");
			TranslateOperandSwizzle(psContext, &psInst->asOperands[0]);
			bcatcstr(glsl, ";\n");
			break;
		case RESOURCE_DIMENSION_TEXTURECUBE:
		case RESOURCE_DIMENSION_TEXTURE1DARRAY:
		case RESOURCE_DIMENSION_TEXTURE2D:
		case RESOURCE_DIMENSION_TEXTURE2DMS:
			AddIndentation(psContext);
			TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_DESTINATION);
			bcatcstr(glsl, " = imageLoad(");
			TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NAME_ONLY);
			bcatcstr(glsl, ", (");
			TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_INTEGER);
			bformata(glsl, ").xy)");
			TranslateOperandSwizzle(psContext, &psInst->asOperands[0]);
			bcatcstr(glsl, ";\n");
			break;
		case RESOURCE_DIMENSION_TEXTURE3D:
		case RESOURCE_DIMENSION_TEXTURE2DARRAY:
		case RESOURCE_DIMENSION_TEXTURE2DMSARRAY:
		case RESOURCE_DIMENSION_TEXTURECUBEARRAY:
			AddIndentation(psContext);
			TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_DESTINATION);
			bcatcstr(glsl, " = imageLoad(");
			TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NAME_ONLY);
			bcatcstr(glsl, ", (");
			TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_INTEGER);
			bformata(glsl, ").xyz)");
			TranslateOperandSwizzle(psContext, &psInst->asOperands[0]);
			bcatcstr(glsl, ";\n");
			break;
		}
		break;
	}
	case OPCODE_STORE_RAW:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//STORE_RAW\n");
#endif
		TranslateShaderStorageStore(psContext, psInst);
		break;
	}
	case OPCODE_STORE_STRUCTURED:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//STORE_STRUCTURED\n");
#endif
		TranslateShaderStorageStore(psContext, psInst);
		break;
	}

	case OPCODE_STORE_UAV_TYPED:
	{
		ResourceBinding* psRes;
		int foundResource;
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//STORE_UAV_TYPED\n");
#endif
		AddIndentation(psContext);

		foundResource = GetResourceFromBindingPoint(RGROUP_UAV,
			psInst->asOperands[0].ui32RegisterNumber,
			&psContext->psShader->sInfo,
			&psRes);

		ASSERT(foundResource);

		bcatcstr(glsl, "imageStore(");
		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_NAME_ONLY);
		switch (psRes->eDimension)
		{
		case REFLECT_RESOURCE_DIMENSION_TEXTURE1D:
			bcatcstr(glsl, ", int(");
			TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_NAME_ONLY);
			bcatcstr(glsl, "), ");
			break;
		case REFLECT_RESOURCE_DIMENSION_TEXTURE2D:
		case REFLECT_RESOURCE_DIMENSION_TEXTURE1DARRAY:
		case REFLECT_RESOURCE_DIMENSION_TEXTURE2DMS:
			bcatcstr(glsl, ", ivec2(");
			TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_NAME_ONLY);
			bcatcstr(glsl, ".xy), ");
			break;
		case REFLECT_RESOURCE_DIMENSION_TEXTURE2DARRAY:
		case REFLECT_RESOURCE_DIMENSION_TEXTURE3D:
		case REFLECT_RESOURCE_DIMENSION_TEXTURE2DMSARRAY:
		case REFLECT_RESOURCE_DIMENSION_TEXTURECUBE:
			bcatcstr(glsl, ", ivec3(");
			TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_NAME_ONLY);
			bcatcstr(glsl, ".xyz), ");
			break;
		case REFLECT_RESOURCE_DIMENSION_TEXTURECUBEARRAY:
			bcatcstr(glsl, ", ivec4(");
			TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_NAME_ONLY);
			bcatcstr(glsl, ".xyzw) ");
			break;
		};

		TranslateOperand(psContext, &psInst->asOperands[2], ResourceReturnTypeToFlag(psRes->ui32ReturnType));
		bformata(glsl, ");\n");

		break;
	}
	case OPCODE_LD_RAW:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//LD_RAW\n");
#endif

		TranslateShaderStorageLoad(psContext, psInst);
		break;
	}

	case OPCODE_ATOMIC_CMP_STORE:
	case OPCODE_IMM_ATOMIC_AND:
	case OPCODE_ATOMIC_AND:
	case OPCODE_IMM_ATOMIC_IADD:
	case OPCODE_ATOMIC_IADD:
	case OPCODE_ATOMIC_OR:
	case OPCODE_ATOMIC_XOR:
	case OPCODE_ATOMIC_IMIN:
	case OPCODE_ATOMIC_UMIN:
	case OPCODE_IMM_ATOMIC_IMAX:
	case OPCODE_IMM_ATOMIC_IMIN:
	case OPCODE_IMM_ATOMIC_UMAX:
	case OPCODE_IMM_ATOMIC_UMIN:
	case OPCODE_IMM_ATOMIC_OR:
	case OPCODE_IMM_ATOMIC_XOR:
	case OPCODE_IMM_ATOMIC_EXCH:
	case OPCODE_IMM_ATOMIC_CMP_EXCH:
	{
		TranslateAtomicMemOp(psContext, psInst);
		break;
	}
	case OPCODE_UBFE:
	case OPCODE_IBFE:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		if (psInst->eOpcode == OPCODE_UBFE)
			bcatcstr(glsl, "//OPCODE_UBFE\n");
		else
			bcatcstr(glsl, "//OPCODE_IBFE\n");
#endif
		AddIndentation(psContext);
		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_DESTINATION);
		bcatcstr(glsl, " = bitfieldExtract(");
		TranslateOperand(psContext, &psInst->asOperands[3], TO_FLAG_NONE);
		bcatcstr(glsl, ", ");
		TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NONE);
		bcatcstr(glsl, ", ");
		TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_NONE);
		bcatcstr(glsl, ");\n");
		break;
	}
	case OPCODE_RCP:
	{
		const uint32_t destElemCount = GetNumSwizzleElements(&psInst->asOperands[0]);
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//RCP\n");
#endif
		AddIndentation(psContext);
		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_DESTINATION);
		bcatcstr(glsl, " = (vec4(1.0) / vec4(");
		TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_NONE);
		bcatcstr(glsl, "))");
		AddSwizzleUsingElementCount(psContext, destElemCount);
		bcatcstr(glsl, ";\n");
		break;
	}
	case OPCODE_F32TOF16:
	{
		const uint32_t destElemCount = GetNumSwizzleElements(&psInst->asOperands[0]);
		const uint32_t s0ElemCount = GetNumSwizzleElements(&psInst->asOperands[1]);
		uint32_t destElem;
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//F32TOF16\n");
#endif
		for (destElem = 0; destElem < destElemCount; ++destElem)
		{
			const char* swizzle[] = { ".x", ".y", ".z", ".w" };

			//unpackHalf2x16 converts two f16s packed into uint to two f32s.

			//dest.swiz.x = unpackHalf2x16(src.swiz.x).x
			//dest.swiz.y = unpackHalf2x16(src.swiz.y).x
			//dest.swiz.z = unpackHalf2x16(src.swiz.z).x
			//dest.swiz.w = unpackHalf2x16(src.swiz.w).x

			AddIndentation(psContext);
			TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_DESTINATION);
			if (destElemCount>1)
				bcatcstr(glsl, swizzle[destElem]);

			bcatcstr(glsl, " = unpackHalf2x16(");
			TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_UNSIGNED_INTEGER);
			if (s0ElemCount > 1)
				bcatcstr(glsl, swizzle[destElem]);
			bcatcstr(glsl, ").x;\n");

		}
		break;
	}
	case OPCODE_F16TOF32:
	{
		const uint32_t destElemCount = GetNumSwizzleElements(&psInst->asOperands[0]);
		const uint32_t s0ElemCount = GetNumSwizzleElements(&psInst->asOperands[1]);
		uint32_t destElem;
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//F16TOF32\n");
#endif
		for (destElem = 0; destElem < destElemCount; ++destElem)
		{
			const char* swizzle[] = { ".x", ".y", ".z", ".w" };

			//packHalf2x16 converts two f32s to two f16s packed into a uint.

			//dest.swiz.x = packHalf2x16(vec2(src.swiz.x)) & 0xFFFF
			//dest.swiz.y = packHalf2x16(vec2(src.swiz.y)) & 0xFFFF
			//dest.swiz.z = packHalf2x16(vec2(src.swiz.z)) & 0xFFFF
			//dest.swiz.w = packHalf2x16(vec2(src.swiz.w)) & 0xFFFF

			AddIndentation(psContext);
			TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_DESTINATION | TO_FLAG_UNSIGNED_INTEGER);
			if (destElemCount>1)
				bcatcstr(glsl, swizzle[destElem]);

			bcatcstr(glsl, " = packHalf2x16(vec2(");
			TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_NONE);
			if (s0ElemCount > 1)
				bcatcstr(glsl, swizzle[destElem]);
			bcatcstr(glsl, ")) & 0xFFFF;\n");

		}
		break;
	}
	case OPCODE_INEG:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//INEG\n");
#endif
		//dest = 0 - src0
		AddIndentation(psContext);
		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_DESTINATION | TO_FLAG_INTEGER);
		bcatcstr(glsl, " = 0 - ");
		TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_NONE | TO_FLAG_INTEGER);
		bcatcstr(glsl, ";\n");
		break;
	}
	case OPCODE_DERIV_RTX_COARSE:
	case OPCODE_DERIV_RTX_FINE:
	case OPCODE_DERIV_RTX:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//DERIV_RTX\n");
#endif
		CallHelper1(psContext, "dFdx", psInst, 0, 1, 1);
		break;
	}
	case OPCODE_DERIV_RTY_COARSE:
	case OPCODE_DERIV_RTY_FINE:
	case OPCODE_DERIV_RTY:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//DERIV_RTY\n");
#endif
		CallHelper1(psContext, "dFdy", psInst, 0, 1, 1);
		break;
	}
	case OPCODE_LRP:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//LRP\n");
#endif
		CallHelper3(psContext, "mix", psInst, 0, 2, 3, 1, 1);
		break;
	}
	case OPCODE_DP2ADD:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//DP2ADD\n");
#endif
		AddIndentation(psContext);
		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_DESTINATION);
		bcatcstr(glsl, " = dot(vec2(");
		TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_NONE);
		bcatcstr(glsl, "), vec2(");
		TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NONE);
		bcatcstr(glsl, ")) + ");
		TranslateOperand(psContext, &psInst->asOperands[3], TO_FLAG_NONE);
		bcatcstr(glsl, ";\n");
		break;
	}
	case OPCODE_POW:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//POW\n");
#endif
		AddIndentation(psContext);
		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_DESTINATION);
		bcatcstr(glsl, " = pow(abs(");
		TranslateOperand(psContext, &psInst->asOperands[1], TO_FLAG_NONE);
		bcatcstr(glsl, "), ");
		TranslateOperand(psContext, &psInst->asOperands[2], TO_FLAG_NONE);
		bcatcstr(glsl, ");\n");
		break;
	}

	case OPCODE_IMM_ATOMIC_ALLOC:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//IMM_ATOMIC_ALLOC\n");
#endif
		AddIndentation(psContext);
		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_DESTINATION);
		bcatcstr(glsl, " = int(atomicCounterIncrement(");
		ResourceName(glsl, psContext, RGROUP_UAV, psInst->asOperands[1].ui32RegisterNumber, 0);
		bformata(glsl, "_counter");
		bcatcstr(glsl, "));\n");
		break;
	}
	case OPCODE_IMM_ATOMIC_CONSUME:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//IMM_ATOMIC_CONSUME\n");
#endif
		AddIndentation(psContext);
		TranslateOperand(psContext, &psInst->asOperands[0], TO_FLAG_DESTINATION);
		//Temps are always signed and atomci counters are always unsigned
		//at the moment.
		bcatcstr(glsl, " = int(atomicCounterDecrement(");
		ResourceName(glsl, psContext, RGROUP_UAV, psInst->asOperands[1].ui32RegisterNumber, 0);
		bformata(glsl, "_counter");
		bcatcstr(glsl, "));\n");
		break;
	}

	case OPCODE_NOT:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//INOT\n");
#endif
		AddIndentation(psContext);
		AddAssignToDest(psContext, &psInst->asOperands[0], SVT_INT, GetNumSwizzleElements(&psInst->asOperands[1]), &numParenthesis);

		bcatcstr(glsl, "~");
		TranslateOperandWithMask(psContext, &psInst->asOperands[1], TO_FLAG_INTEGER, GetOperandWriteMask(&psInst->asOperands[0]));
		AddAssignPrologue(psContext, numParenthesis);
		break;
	}
	case OPCODE_XOR:
	{
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//XOR\n");
#endif

		CallBinaryOp(psContext, "^", psInst, 0, 1, 2, SVT_UINT);
		break;
	}
	case OPCODE_RESINFO:
	{

		const RESOURCE_DIMENSION eResDim = psContext->psShader->aeResourceDims[psInst->asOperands[2].ui32RegisterNumber];
		const RESINFO_RETURN_TYPE eResInfoReturnType = psInst->eResInfoReturnType;
		uint32_t destElemCount = GetNumSwizzleElements(&psInst->asOperands[0]);
		uint32_t destElem;
#ifdef _DEBUG
		AddIndentation(psContext);
		bcatcstr(glsl, "//RESINFO\n");
#endif

		for (destElem = 0; destElem < destElemCount; ++destElem)
		{
			const char* swizzle[] = { ".x", ".y", ".z", ".w" };

			GetResInfoData(psContext, psInst, psInst->asOperands[2].aui32Swizzle[destElem], destElem);
		}

		break;
	}


	case OPCODE_DMAX:
	case OPCODE_DMIN:
	case OPCODE_DMUL:
	case OPCODE_DEQ:
	case OPCODE_DGE:
	case OPCODE_DLT:
	case OPCODE_DNE:
	case OPCODE_DMOV:
	case OPCODE_DMOVC:
	case OPCODE_DTOF:
	case OPCODE_FTOD:
	case OPCODE_DDIV:
	case OPCODE_DFMA:
	case OPCODE_DRCP:
	case OPCODE_MSAD:
	case OPCODE_DTOI:
	case OPCODE_DTOU:
	case OPCODE_ITOD:
	case OPCODE_UTOD:
	default:
	{
		ASSERT(0);
		break;
	}
	}

	if (psInst->bSaturate) //Saturate is only for floating point data (float opcodes or MOV)
	{
		int dstCount = GetNumSwizzleElements(&psInst->asOperands[0]);
		AddIndentation(psContext);
		AddAssignToDest(psContext, &psInst->asOperands[0], SVT_FLOAT, dstCount, &numParenthesis);
		bcatcstr(glsl, "clamp(");

		TranslateOperand(psContext, &psInst->asOperands[0], TO_AUTO_BITCAST_TO_FLOAT);
		bcatcstr(glsl, ", 0.0, 1.0)");
		AddAssignPrologue(psContext, numParenthesis);
	}
}

static int IsIntegerImmediateOpcode(OPCODE_TYPE eOpcode)
{
	switch (eOpcode)
	{
	case OPCODE_IADD:
	case OPCODE_IF:
	case OPCODE_IEQ:
	case OPCODE_IGE:
	case OPCODE_ILT:
	case OPCODE_IMAD:
	case OPCODE_IMAX:
	case OPCODE_IMIN:
	case OPCODE_IMUL:
	case OPCODE_INE:
	case OPCODE_INEG:
	case OPCODE_ISHL:
	case OPCODE_ISHR:
	case OPCODE_ITOF:
	case OPCODE_USHR:
	case OPCODE_AND:
	case OPCODE_OR:
	case OPCODE_XOR:
	case OPCODE_BREAKC:
	case OPCODE_CONTINUEC:
	case OPCODE_RETC:
	case OPCODE_DISCARD:
		//MOV is typeless.
		//Treat immediates as int, bitcast to float if necessary
	case OPCODE_MOV:
	case OPCODE_MOVC:
	{
		return 1;
	}
	default:
	{
		return 0;
	}
	}
}

int InstructionUsesRegister(const Instruction* psInst, const Operand* psOperand)
{
	uint32_t operand;
	for (operand = 0; operand < psInst->ui32NumOperands; ++operand)
	{
		if (psInst->asOperands[operand].eType == psOperand->eType)
		{
			if (psInst->asOperands[operand].ui32RegisterNumber == psOperand->ui32RegisterNumber)
			{
				if (CompareOperandSwizzles(&psInst->asOperands[operand], psOperand))
				{
					return 1;
				}
			}
		}
	}
	return 0;
}

void MarkIntegerImmediates(HLSLCrossCompilerContext* psContext)
{
	const uint32_t count = psContext->psShader->asPhase[MAIN_PHASE].pui32InstCount[0];
	Instruction* psInst = psContext->psShader->asPhase[MAIN_PHASE].ppsInst[0];
	uint32_t i;

	for (i = 0; i < count;)
	{
		if (psInst[i].eOpcode == OPCODE_MOV && psInst[i].asOperands[1].eType == OPERAND_TYPE_IMMEDIATE32 &&
			psInst[i].asOperands[0].eType == OPERAND_TYPE_TEMP)
		{
			uint32_t k;

			for (k = i + 1; k < count; ++k)
			{
				if (psInst[k].eOpcode == OPCODE_ILT)
				{
					k = k;
				}
				if (InstructionUsesRegister(&psInst[k], &psInst[i].asOperands[0]))
				{
					if (IsIntegerImmediateOpcode(psInst[k].eOpcode))
					{
						psInst[i].asOperands[1].iIntegerImmediate = 1;
					}

					goto next_iteration;
				}
			}
		}
	next_iteration:
		++i;
	}
}
